La norme C99 dit dans 6.5.16: 2:
Un opérateur d'assignation doit avoir une valeur l 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, qui n'a pas de type incomplet, qui n'a pas de type qualifié const et qui, s'il s'agit d'une structure ou d'union, n'a pas de membre (y compris, récursivement, tout membre ou élément de tous les agrégats ou unions contenus) avec un type qualifié const.
Maintenant, considérons un non const
struct
avec un const
champ.
typedef struct S_s {
const int _a;
} S_t;
Par défaut, le code suivant est un comportement non défini (UB):
S_t s1;
S_t s2 = { ._a = 2 };
s1 = s2;
Le problème sémantique avec cela est que l'entité englobante ( struct
) doit être considérée comme inscriptible (non en lecture seule), à en juger par le type déclaré de l'entité ( S_t s1
), mais ne doit pas être considérée comme inscriptible par le libellé de la norme (les 2 clauses en haut) à cause du const
champ _a
. La norme ne rend pas clair pour un programmeur lisant le code que l'affectation est en fait un UB, car il est impossible de dire cela sans la définition du struct S_s ... S_t
type.
De plus, l'accès en lecture seule au champ n'est de toute façon imposé que syntaxiquement. Il n'y a aucun moyen que certains const
champs de non const
struct
soient vraiment placés dans un stockage en lecture seule. Mais une telle formulation de la norme proscrit le code qui rejette délibérément le const
qualificatif des champs dans les procédures d'accès de ces champs, comme ça ( Est-ce une bonne idée de const-qualifier les champs de structure en C? ):
(*)
#include <stdlib.h>
#include <stdio.h>
typedef struct S_s {
const int _a;
} S_t;
S_t *
create_S(void) {
return calloc(sizeof(S_t), 1);
}
void
destroy_S(S_t *s) {
free(s);
}
const int
get_S_a(const S_t *s) {
return s->_a;
}
void
set_S_a(S_t *s, const int a) {
int *a_p = (int *)&s->_a;
*a_p = a;
}
int
main(void) {
S_t s1;
// s1._a = 5; // Error
set_S_a(&s1, 5); // OK
S_t *s2 = create_S();
// s2->_a = 8; // Error
set_S_a(s2, 8); // OK
printf("s1.a == %d\n", get_S_a(&s1));
printf("s2->a == %d\n", get_S_a(s2));
destroy_S(s2);
}
Donc, pour une raison quelconque, pour qu'un ensemble struct
soit en lecture seule, il suffit de le déclarerconst
const S_t s3;
Mais pour qu'un ensemble ne struct
soit pas en lecture seule, il ne suffit pas de le déclarer sans const
.
Ce que je pense serait mieux, c'est:
- Contraindre la création de non-
const
structures avec desconst
champs et émettre un diagnostic dans un tel cas. Cela indiquerait clairement que lesstruct
champs en lecture seule contenant sont eux-mêmes en lecture seule. - Définir le comportement en cas d'écriture dans un
const
champ appartenant à une non-const
structure comme rendre le code ci-dessus (*) conforme au Standard.
Sinon, le comportement n'est pas cohérent et difficile à comprendre.
Alors, quelle est la raison pour laquelle C Standard considère const
-ness récursivement, comme il le dit?