Der C99-Standard sagt in 6.5.16: 2:
Ein Zuweisungsoperator muss einen modifizierbaren Wert als linken Operanden haben.
und in 6.3.2.1:1:
Ein modifizierbarer Wert ist ein Wert, der keinen Array-Typ hat, keinen unvollständigen Typ hat, keinen const-qualifizierten Typ hat und, wenn es sich um eine Struktur oder Vereinigung handelt, kein Mitglied hat (einschließlich rekursiv eines Mitglieds) oder Element aller enthaltenen Aggregate oder Gewerkschaften) mit einem const-qualifizierten Typ.
Betrachten wir nun ein Nicht- const structmit- constFeld.
typedef struct S_s {
const int _a;
} S_t;
Standardmäßig ist der folgende Code undefiniertes Verhalten (UB):
S_t s1;
S_t s2 = { ._a = 2 };
s1 = s2;
Das semantische Problem dabei ist, dass die einschließende Entität ( struct) als beschreibbar (nicht schreibgeschützt) betrachtet werden sollte, gemessen am deklarierten Typ der Entität ( S_t s1), aber nicht als beschreibbar durch den Wortlaut des Standards (die 2 Klauseln) oben) wegen des constFeldes _a. Der Standard macht es für einen Programmierer, der den Code liest, unklar, dass die Zuweisung tatsächlich eine UB ist, da es unmöglich ist, dies ohne die Definition des struct S_s ... S_tTyps zu sagen .
Darüber hinaus wird der schreibgeschützte Zugriff auf das Feld ohnehin nur syntaktisch erzwungen. Es gibt keine Möglichkeit, dass einige constFelder, die nicht vorhanden const structsind, wirklich schreibgeschützt gespeichert werden. Ein solcher Wortlaut von Standard verbietet jedoch den Code, der das constQualifikationsmerkmal von Feldern in Accessor-Prozeduren dieser Felder absichtlich wegwirft ( Ist es eine gute Idee, die Strukturfelder in C zu qualifizieren? ):
(*)
#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);
}
Aus irgendeinem Grund reicht es aus, ein Ganzes structals schreibgeschützt zu deklarierenconst
const S_t s3;
Aber damit ein Ganzes structnicht schreibgeschützt ist, reicht es nicht aus, es ohne zu deklarieren const.
Was ich für besser halte, ist entweder:
- Einschränkung der Erstellung von Nichtstrukturen
constmitconstFeldern und Ausgabe einer Diagnose in einem solchen Fall. Das würde deutlich machen, dass diestructenthaltenden schreibgeschützten Felder selbst schreibgeschützt sind. - Definieren des Verhaltens beim Schreiben in ein
constFeld, das zu einerconstNichtstruktur gehört, um den obigen Code (*) mit dem Standard kompatibel zu machen.
Ansonsten ist das Verhalten nicht konsistent und schwer zu verstehen.
Was ist der Grund für C Standard, const-ness rekursiv zu betrachten , wie es heißt?