En utilisant avr-gcc comme exemple, les types int sont spécifiés pour avoir une largeur de 16 bits. L'exécution d'opérations sur des opérandes 8 bits en C entraîne la conversion de ces opérandes en types int 16 bits en raison de la promotion des nombres entiers en C. Cela signifie-t-il que toutes les opérations arithmétiques 8 bits sur un AVR prendront beaucoup plus de temps si elles sont écrites en C que si écrit en assemblage en raison de la promotion de l'entier C?
microcontroller
avr
c
pr871
la source
la source
Réponses:
Longue histoire courte:
La promotion d'entier en 16 bits a toujours lieu - la norme C l'impose. Mais le compilateur est autorisé à optimiser le calcul jusqu'à 8 bits (les compilateurs de systèmes embarqués sont généralement assez bons pour de telles optimisations), s'il peut déduire que le signe sera le même qu'il aurait été si le type avait été promu.
Ce n'est pas toujours le cas! Les modifications de signature implicites causées par la promotion d'entiers sont une source courante de bogues dans les systèmes embarqués.
Une explication détaillée peut être trouvée ici: Règles de promotion de type implicite .
la source
comme fun1 attendu est tous les pouces, tout comme les mathématiques 16 bits
Bien que techniquement incorrect car il s'agit d'un ajout 16 bits appelé par le code, même non optimisé, ce compilateur a supprimé l'adc en raison de la taille du résultat.
pas vraiment surpris ici que la promotion se produise, les compilateurs ne le faisaient pas, je ne sais pas quelle version a fait que ce début se produise, je l'ai rencontré tôt dans ma carrière et malgré les compilateurs faisant la promotion hors service (comme ci-dessus), faisant la promotion même si je lui a dit de faire des mathématiques uchar, pas surpris.
et l'idéal, je sais que c'est 8 bits, je veux un résultat 8 bits alors je lui ai simplement dit de faire 8 bits tout au long.
Donc, en général, il vaut mieux viser la taille du registre, qui est idéalement la taille d'un (u) int, pour un mcu 8 bits comme celui-ci, les auteurs du compilateur ont dû faire un compromis ... Le point étant de ne pas prendre l'habitude de utiliser uchar pour les mathématiques que vous savez n'a pas besoin de plus de 8 bits comme lorsque vous déplacez ce code ou écrivez un nouveau code comme celui-ci sur un processeur avec des registres plus grands, le compilateur doit maintenant commencer à masquer et à étendre les signes, ce que certains font nativement dans certaines instructions, et d'autres non.
forcer 8 bits coûte plus cher. J'ai triché un peu / beaucoup, j'aurais besoin d'exemples un peu plus compliqués pour en voir plus de manière juste.
EDIT basé sur la discussion des commentaires
pas de surprise. Bien que l'optimiseur ait laissé cette instruction supplémentaire, ne pouvez-vous pas utiliser ldi sur r19? (Je connaissais la réponse quand je l'ai posée).
EDIT2
pour avr
pour éviter la mauvaise habitude ou pas la comparaison 8 bits
il est clair que l'optimisation était activée ne prend qu'une seconde pour essayer avec votre propre compilateur pour voir comment il se compare à ma sortie, mais de toute façon:
Et oui, utiliser des octets pour des variables de taille octet, certainement sur un avr, pic, etc., vous fera économiser de la mémoire et vous voulez vraiment essayer de le conserver ... si vous l'utilisez réellement, mais comme indiqué ici le moins possible est va être en mémoire, autant dans les registres que possible, donc les économies de flash viennent en n'ayant pas de variables supplémentaires, les économies de RAM peuvent être réelles ou non.
la source
unsigned char
donc il doit effectuer la promotion en 16 bits, comme requis par la norme.(a<<8)|b
est toujours incorrect pour tout système avecint
16 bits.a
sera implicitement promuint
auquel est signé. En casa
tenu une valeur dans le MSB, vous finissez par décalage que les données dans le bit de signe d'un nombre de 16 bits, qui invoque un comportement non défini.Pas nécessairement, car les compilateurs modernes font un bon travail pour optimiser le code généré. Par exemple, si vous écrivez
z = x + y;
où se trouvent toutes les variablesunsigned char
, le compilateur doit les promouvoir enunsigned int
avant d'effectuer les calculs. Cependant, puisque le résultat final sera exactement le même sans la promotion, le compilateur générera du code qui ajoute simplement des variables 8 bits.Bien sûr, ce n'est pas toujours le cas, par exemple le résultat de
z = (x + y)/2;
dépendra de l'octet supérieur, donc la promotion aura lieu. Il peut encore être évité sans recourir à l'assemblage en redirigeant le résultat intermédiaire versunsigned char
.Certaines de ces inefficacités peuvent être évitées en utilisant les options du compilateur. Par exemple, de nombreux compilateurs 8 bits ont un pragma ou un commutateur de ligne de commande pour adapter les types d'énumération à 1 octet, au lieu de
int
celui requis par C.la source
int
, car ilchar
n'aura probablement pas le même rang de conversion queint
sur n'importe quelle plate-forme.int
(oui, c'est incohérent). C11 6.7.2.2Each enumerated type shall be compatible with char, a signed integer type, or an unsigned integer type. The choice of type is implementation-defined...