Je suis d'accord avec le fait de préféré les fonctions préfixées par un f.
Tu as des systèmes uniquement en 32 bits et dont les uint64 n'existent pas.
Le type uint64_t est optionnel (voir la norme C99 à la section 7.18.1.1 Exact-width integer types, , mais pas que sur systèmes 32 bits. Et ce n'est par parce que tu es sur un système 32 bits que tu n'as pas un type qui contient au moins 64 bits. Voir la norme C99 à la section 7.18.1.2 Minimum-width integer types, point 3 :
The follo
wing types are required:
int_least8_t
int_least16_t
int_least32_t
int_least64_t
uint_least8_t
uint_least16_t
uint_least32_t
uint_least64_t
All other types of this form are optional
Si tu as besoin de 64 bits (non signé), tu peux utiliser uint_least64_t. Sur un système avec un bus 32 bits, on peut s'attendre à ce que le compilateur fasse lui-même les 2 accès sur le bus et la concaténation en assembleur. Ca peut arriver sur un compilateur non-conforme à la norme. Si on pense que ça a des grandes chances d'arriver, on peut déjà anticiper. Sinon, on utilise ce que fourni la norme pour plus de simplicité. Je me demande par contre dans le cas particulier du POsi on ne peut pas avoir un problème d'endianess...
Dans les systèmes embarqués tu n'as pas toujours le choix, tu dois parfois envoyer un nombre sur 16 bits sur un bus de 8 bits, et dans ce cas on fait passer par paquets. Etant donné qu'on ne sait pas sur quel système ça s'opère, il est toujours bon d'avoir une solution qui sera toujours meilleure à prendre qu'aucune solution
Il faut bien penser qu'il y a d'un côté le bus du CPU pour accéder aux mémoires, sur lequel l'assembleur généré à partir d'un code C peut faire lui même les différents accès si le bus est trop petit. C'est si on a un compilateur décent sur une architecture moderne en tout cas. J'ai fait un test pour Cortex-M3, une architecture 32 bits avec un langage assembleur assez lisible. Accessoirement, ce CPU a été pensé pour être programmable efficacement en C.
Voici le code C qui nous intéresse :
Voici l'assembleur généré (j'ai utilisé O1 pour avoir un truc qui me semble correct, en O0 je trouvais qu'il s'embêtait pour pas grand chose en passant tout sur la stack) :
pgradot@pgradot-VirtualBox:~/Documents/C$ arm-none-eabi-gcc -O1 -c main.c -mthumb -mcpu=cortex-m3 && arm-none-eabi-objdump -d main.o
main.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <f_32>:
0: 3001 adds r0, #1
2: 4770 bx lr
00000004 <f_64>:
4: 3001 adds r0, #1
6: f141 0100 adc.w r1, r1, #0
a: 4770 bx lr
Sur Cortex-M, les paramètres sont passés de r0 à r3 et la valeur de retour est mise à partir de r0. Tous ces registres sont 32 bits.
- On voit qu'avec un nombre 32 bits (exact) est passé dans r0 et qu'on ajoute simple 1 à r0. On retourne directement, la valeur résultante étant déjà dans le bon registre.
- On voit qu'un nombre 64 bits au moins fait exactement 32 bits et est passé sur 2 registres, r0 et r1. L'assembleur ajoute 1 à la partie basse (on est en little endian) et 0 à la partie haute. On retourne ensuite directement, la valeur de retour étant déjà dans les bons registres.
D'un autre côté les bus périphériques pour lesquelles tu fais souvent manuellement les passages par paquets. Si je souhaite écrire mes nombres sur une ligne série via une UART, le port UART du CPU fait 8 bits donc je suis obligé de découper d'envoyer moi-même byte par byte.
Partager