Quel compilateur C99 (Clang vs. GCC) est le plus proche des champs de structure standard sur const?

J’ai un code comme ça:

$ cat test.c #include  typedef struct { const int x; } SX; static SX mksx(void) { return (SX) { .x = 10 }; } void fn(void) { SX sx; while((sx = mksx()).x != 20) { printf("stupid code!"); } } 

Et 2 avis sur son exactitude:

 $ for i in gcc clang; do echo "$i SAYS:"; $i -c -std=c99 -pedantic -Werror test.c; done gcc SAYS: test.c: In function 'fn': test.c:15:2: error: assignment of read-only variable 'sx' while((sx = mksx()).x != 20) ^ clang SAYS: 

Quel compilateur a raison?

La norme C99 dit dans 6.5.16: 2:

Un opérateur d’affectation doit avoir une valeur modifiable comme opérande gauche.

et en 6.3.2.1:1:

Une lvalue modifiable est une lvalue qui n’a pas de type tableau, n’a pas de type incomplet, n’a pas de type qualifié qualifié et, s’il s’agit d’une structure ou d’union, n’a pas de membre (y compris, de manière récursive, un membre ou élément de tous les agrégats ou unions contenus) avec un type qualifié de const .

Donc, GCC a raison de prévenir.

De plus, la clause 6.5.16: 2 se trouve dans la section «Contraintes» de la norme C99. Par conséquent, un compilateur conforme est requirejs pour émettre un diagnostic pour un programme qui rompt la clause. C’est toujours un comportement indéfini: le compilateur peut toujours faire ce qu’il veut après l’émission du diagnostic. Mais il doit y avoir un message. En conséquence, Clang se comporte ici de manière non conforme.

const variable const ne peut pas être modifiée après l’initialisation, sinon c’est un comportement indéfini.

Comme il s’agit d’un comportement indéfini, je pense que l’on peut dire que gcc et clang suivent la norme. (Bien que le choix de gcc semble meilleur, il mérite un avertissement) (Voir EDIT ci-dessous)

La seule façon de donner à la variable x une valeur avec un comportement défini est de l’initialiser:

 SX sx = { .x = 10 }; 

EDIT : Comme le commente @ Keith Thompson ci-dessous, il n’ya pas que le comportement indéfini dans ce cas:

C99 §6.5.16 Opérateurs d’assignation

Contraintes

Un opérateur d’affectation doit avoir une valeur modifiable comme opérande gauche.

C’est une contrainte, et selon:

C99 §5.1.1.3 Diagnostic

Une implémentation conforme doit produire au moins un message de diagnostic (identifié de manière définie par l’implémentation) si une unité de traduction en cours de prétraitement ou une unité de traduction contient une violation d’une règle ou contrainte de syntaxe, même si le comportement est également spécifié explicitement comme indéfini ou implémentation. défini. Les messages de diagnostic ne doivent pas nécessairement être produits dans d’autres circonstances.

Un compilateur doit émettre un diagnostic pour tout programme violant une contrainte.

Retour à la question, gcc est correct, génère un avertissement, mais pas Clang.