2010-03-03 15 views
2

Ce code a un bug intéressant:Ordre d'évaluation d'affectation (Ai-je trouvé mon premier bug du compilateur?)

some_struct struct_array1[10] = {0}; 
some_struct struct_array2[10] = {0} 
int i; 

for (i = 0; 
    i < sizeof(struct_array1)/sizeof(struct_array1[0]); 
    struct_array1[i].value = struct_array2[i++].value = 1) 
    ; 

Pour la plupart des compilateurs, les résultats de code ci-dessus en définissant le champ « valeur » de tous struct dans les tableaux respectifs à 1. Cependant, pour un compilateur spécifique (appelons-le xcc), les structures de struct_array1 ne sont pas initialisées correctement. Le champ "value" est mis à 0 pour toutes les structures, ce qui m'a surpris.

Le code suivant fonctionne comme prévu sur tous les compilateurs:

for (i = 0; 
    i < sizeof(struct_array1)/sizeof(struct_array1[0]); 
    i++) 
{ 
    struct_array1[i].value = struct_array2[i].value = 1; 
} 

Maintenant, je suis complètement ici, ou le compilateur offensant « de XCC » afficher simplement un bug?

Je ne trouve rien qui affiche un comportement spécifique à l'implémentation dans le premier extrait de code; d'après ce que je comprends, l'incrémentation de postfix devrait avoir préséance sur les affectations, et les affectations devraient être évaluées de droite à gauche. Il ne devrait y avoir rien de bizarre avec le premier extrait de code, sauf que c'est un peu illisible.

+4

ce n'est pas un bogue de compilateur, c'est un bogue de programmeur: le code implique un comportement non défini et est donc invalide C – Christoph

+0

http://catb.org/~esr/faqs/smart-questions.html#id382249 –

+0

Je vous suggère de google up comportement indéfini. –

Répondre

8

Vous avez appelé un comportement indéfini, car il modifie i et récupère également sa valeur dans un but autre que le calcul de la nouvelle valeur, sans un point de séquence intermédiaire.

La partie pertinente de la norme C99 est présent paragraphe à l'article 6.5:

entre la séquence précédente et suivante point de l'objet a la valeur stockée modifiée au plus une fois par l'évaluation d'un expression. En outre, la valeur antérieure doit être en lecture seule pour déterminer la valeur à stockée.

+0

Ah, bien sûr. Cela n'explique pas pourquoi le second exemple fonctionne, mais puisque son comportement est indéfini, je suppose qu'il ne doit pas être cohérent :-) – Christoffer

+0

Le deuxième exemple est OK car 'i' n'est pas modifié - il est juste lu deux fois (l'incrément arrive dans une expression séparée, après un point de séquence). Les deux objets qui sont * modifiés * sont distincts (donc c'est OK aussi). – caf

+0

Ouais, je suis un peu gêné de ne pas le voir pour moi-même, je suppose que j'avais besoin d'un autre ensemble d'yeux pour repérer le problème.(Pour ma défense, je voudrais ajouter que le patch que je suis en train de réviser était ~ 500 lignes de code, c'était juste un des problèmes :-) – Christoffer

5

struct_array1[i].value = struct_array2[i++].value = 1

Je pense que ce comportement non défini parce i++ n'est pas garanti pour compléter tous ses effets secondaires jusqu'au prochain point de séquence est atteinte. Le point de séquence suivant est le 'imaginaire' ; à la fin de l'instruction. C'est un piège commun, je pense que vous pouvez trouver de nombreux sujets sur SO se rapportant à cela, il suffit de rechercher des points de séquence.

+0

Ceci est vrai. +1 de moi. –

0

Supposons que nous fait de ne pas effectuer plus d'une évaluation pour une même variable, dans signle

expression

. Si nous faisons cela, ce sera un comportement indéfini.