16

Ich wollte sehen, ob ich eine globale Variable initialisieren könnte sich Punkt:Initialisieren von zirkulären Daten in C. Ist dieser gültige C-Code gemäß einem Standard?

#include <stdio.h> 
struct foo { struct foo *a, *b; } x = { &x, &x }; 
int main() 
{ 
    printf("&x = %p, x.a = %p, x.b = %p\n", &x, x.a, x.b); 
    return 0; 
} 

Dieser Code kompiliert und ausgeführt wie bei gcc (alle drei Zeiger Druck identisch) erwartet.

Ich möchte wissen:

  1. Ist das zuverlässig?
  2. Ist dieser Standard?
  3. Ist das tragbar?

EDIT: Nur um zu klären, ich bin die Verfügbarkeit der Adresse x in seinem eigenen initializer in Frage stellt.

+0

dort ist ein Problem: '% p' erwartet ein' void * ', aber die Argumente sind' struct foo * 's. –

+0

@DanielFischer Erlaubt nicht stille Konvertierungen zu und von' void * 'von irgendeinem anderen Zeiger, um zu erlauben Funktionen wie "malloc", um ohne explizite Konvertierungen zu arbeiten? – Matt

+1

Es tut, aber nur auf Zuweisung. Wenn man Zeug zu 'printf' übergibt, geschieht keine solche Umwandlung (varargs, überhaupt keine Überprüfung). So' printf' bekommt 'struct foo *' s, aber die Formatzeichenfolge benötigt 'void *'. Ihr Compiler sollte Sie davor warnen (wenn Sie die Warnstufe erhöhen). Im Grunde ist das sogar undefiniertes Verhalten, obwohl es auf den meisten gängigen Plattformen funktioniert (der Standard garantiert nicht, dass alle Zeiger die gleiche Größe und Struktur haben, aber normalerweise haben sie). –

Antwort

8

Dies ist Standard-C-Code

Dieser Absatz des mächtigen Standard gestattet es (Hervorhebung von mir):..

(C99, 6.2. 1p7) "Struktur-, Union- und Enumeration-Tags haben den Umfang t Hat beginnt unmittelbar nach dem Erscheinen des Tags in einem Typspezifizierer, der das Tag deklariert. Jede Enumerationskonstante hat einen Gültigkeitsbereich, der unmittelbar nach dem Erscheinen des definierenden Enumerators in einer Enumeratorliste beginnt. Jeder andere Bezeichner hat einen Gültigkeitsbereich, der unmittelbar nach dem Abschluss seines Deklarators beginnt. "

Informationen, dass beachten Sie den letzten Satz von 6.2.1p7 zu veranschaulichen, das Buch‚verwendet der neue C Standard‘von Derek M. Jones ein Beispiel ähnlich wie bei Ihnen:

struct T {struct T *m;} x = /* declarator complete here. */ {&x}; 
+0

Danke, das ist nur die Antwort, die ich suchte! – Matt

+0

@Matt du bist willkommen! – ouah

8

Ja zu allen oben genannten. Sie haben ein paar Zeiger, die Sie mit der gleichen Adresse initialisieren, also haben sie die gleiche Adresse und das ist die gleiche Adresse, mit der Sie sie initialisierten.

Interessanterweise ist x.a auch garantiert auf sich selbst zu zeigen (dh, das erste Element in einer Struktur ist garantiert am Anfang der Struktur, also ein Zeiger auf die Struktur, umgewandelt in den Typ der erste Element, ist garantiert, dass das erste Element Punkt

+0

Was ich in Frage gestellt wurde, war, ob die Adresse von 'x' in der Initialisierungsklausel verfügbar ist. Auch haben Sie Recht, dass 'xa' auf den gleichen Ort wie sich selbst zeigt, aber der Typ ist anders' xa' ist ein 'struct foo *' und sollte auf ein 'struct foo' zeigen, das nicht den gleichen Typ wie sich selbst hat . – Matt

+0

@Matt: Ja, die Adresse ist ein rvalue (im Wesentlichen eine Konstante), also aus der Sicht des Programms, das ist nicht viel anders als etwas wie "int x = 1234;' –