2015-10-26 10 views
13

Ich habe zwei structs wieWirf einen Zeiger auf verschiedene Strukturen, die in C89 bedeutungsvoll sind?

struct X { 
    int x; 
    double *y; 
}; 

struct Y { 
    int a; 
    double *b; 
    char c; 
}; 

ist ein Zeiger auf struct Y auf einen Zeiger auf struct X Gießen konsequent in angemessener Weise verhalten, garantiert durch die C89-Standard (das heißt x->x und x->y zu y->a und y->b jeweils entsprechen)? Weniger wichtig, aber wirklich cool wäre, wenn Sie auch wissen, passieren, hält dies auch für die späteren Normen wahr (zB C11) und andere Sprachen, die mit C (zB C++ XX, Objective-C signifikant syntaktische und semantische Überlappung)

+0

Ich weiß nicht, über C++, aber es scheint, für alle Versionen von C. Viele Softwarepakete stützen sich auf das wahr. – chqrlie

+2

C++ ist eine andere Sprache, nicht eine neuere Version von C –

+0

@ M. M Messe Punkt. Obwohl, ich glaube, es natürlich ist dieses Verhalten in anderen Sprachen neugierig zu sein, die eine Menge Überschneidungen mit C. haben Will bearbeiten klarer machen – math4tots

Antwort

7

Es ist nicht definiertes Verhalten. Python relied on this before and had to fix that. Wenn Sie struct Ystruct X als erstes Element umfassen, können Sie, dass für einen ähnlichen Effekt verwenden:

struct Y { 
    struct X a; 
    char c; 
}; 

struct Y y; 
struct X *x = (struct X *) &y; /* legal! */ 

Es gibt auch einen Sonderfall für die Gewerkschaften:

struct X { 
    int x; 
    double *y; 
}; 

struct Y { 
    int a; 
    double *b; 
    char c; 
}; 

union XY { 
    struct X x; 
    struct Y y; 
}; 

union XY xy; 
xy.x.x = 0; 
printf("%d\n", xy.y.a); /* legal! */ 

In späteren Versionen des C-Standard erforderlich ist, wird der Compiler nur X und Y Objekte Aliasing einander zu behandeln, wenn eine Vereinigung Definition wie folgt tatsächlich in Umfang, aber in C89, hat es meist eine solche Definition zu übernehmen irgendwo existiert. Das immer noch nicht macht es sicher, ein struct Y * zu einem struct X * zu werfen, obwohl; wenn der Compiler weiß, dass eine bestimmtes struct Y nicht Teil einer Vereinigung ist, kann es annehmen, noch dass ein struct X * kann unmöglich alias es.

+0

Cool danke, das ist perfekt! Ich hatte erwartet, dass meine ideale Antwort den C-Standard referenzieren würde, aber um ehrlich zu sein, vertraue ich den Python-Jungs, dass sie ihr Ding wirklich kennen, und wenn sie sagen, dass es ein undefiniertes Verhalten in einem offiziellen PEP ist, bin ich ziemlich geneigt ihnen zu vertrauen. – math4tots

+0

Der Standard deklariert zwei Strukturen als "kompatibel", wenn sie dieselben Mitglieder in der gleichen Reihenfolge haben (aber in der Tat gleiche Namen anfordern, auch ... zuerst übersehen) ... zweifle immer noch an dieser Interpretation. –

+0

@FelixPalmen: Damit 'struct X' und' struct Y' kompatibel sind, müsste 'struct X' am Ende dieses' char'-Member haben. – user2357112

2

C89 erlaubt die Umwandlung, durch eingegossene, der einen Zeiger auf einen Objekttyp in einen Zeiger auf einen anderen Objekttyp.

Bevor wir überhaupt zur Dereferenzierung kommen, ist der konvertierte Zeiger garantiert nur dann gültig, wenn der referenzierte Typ des ursprünglichen Zeigers mindestens die gleiche Ausrichtung wie der Typ erfordert, auf den der Ergebniszeiger verweist. Die Ausrichtung ist vollständig implementierungsabhängig. In Ihrem speziellen Beispiel ist es wahrscheinlich, aber nicht garantiert, dass die beiden struct Typen die gleiche Ausrichtung Anforderung haben.

Angenommen, dass die Konvertierung einen gültigen Zeiger erzeugt, definiert der Standard nicht genau, wie struct Mitglieder innerhalb der Darstellung eines struct Objekts angeordnet sind. Die Mitglieder müssen in der gleichen Reihenfolge erscheinen wie in der struct Definition, und es dürfen keine Polsterung vor dem ersten sein, aber keine weiteren Details festgelegt. In Ihrem Beispiel wird also gewährleistet, dass X->x zu Y->a entsprechen wird (unter der Annahme, wieder, dass der umgewandelte Zeiger in erster Linie gültig ist), aber nicht definiert, ob X->y wird entsprechen Y->b.

+0

Wie kann das Hinzufügen eines 'char'-Members möglicherweise die Anforderungen an die Strukturausrichtung erhöhen? Der Ausschuss sollte aufgeben, den DS9K zu unterstützen. – chqrlie

+0

@chqrlie, es geht nicht darum, ob das Hinzufügen eines 'char'-Mitglieds * die Ausrichtungsanforderung erhöhen sollte, es geht darum, ob es * erlaubt * ist, dies zu tun. Es ist. Betrachten Sie als nicht allzu konstruiertes Beispiel dennoch ein System, das 'struct's mit 8 Byte Membern auf 8-Byte-Grenzen ausrichtet, aber größere' struct's auf 16-Byte-Grenzen ausrichtet. Wenn ein solches System auf einer Maschine läuft, auf der "int" und "double *" beide 32 Bits breit sind, dann würde genau das OPs-Beispiel eine andere Ausrichtungsanforderung für seine zwei "struct" -Typen darstellen. –

+0

Für was es jedoch Wert ist, Ausrichtung ist Implementierung definiert, nicht unspezifiziert oder undefiniert. Das bedeutet, dass Sie sich darauf verlassen können, dass konforme Implementierungen angegeben werden, und wenn Sie für eine bestimmte Implementierung schreiben, kann sich Ihr Code darauf verlassen, was diese Implementierung spezifiziert. –