16

Volevo vedere se riuscivo a inizializzare una variabile globale per puntare a se stesso:Inizializzazione di dati circolari in C. Questo codice C valido è conforme a qualsiasi 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; 
} 

Questo codice viene compilato ed eseguito come previsto con gcc (tutti e tre puntatori di stampa in modo identico).

Voglio sapere:

  1. È questo affidabile?
  2. È questo standard?
  3. È portatile?

EDIT: Giusto per chiarire, io sono in discussione la disponibilità dell'indirizzo di x nella propria inizializzazione.

+0

C'è un problema: '% p' si aspetta un' void * ', ma gli argomenti sono' struct foo * 's. –

+0

@DanielFischer Non C consente le conversioni silenziose da e verso' void * 'da qualsiasi altro puntatore per consentire funzioni come 'malloc' per funzionare senza conversioni esplicite? – Matt

+1

Lo fa, ma solo su assegnamento. Passando roba a' printf', non avviene alcuna conversione (varargs, nessun tipo di controllo). ottiene 'struct foo *' s, ma la stringa di formato richiede 'void *'. Il compilatore dovrebbe avvertirti di questo (se si attiva il livello di avviso). Pedanticamente, anche questo comportamento è indefinito, anche se funzionerà come previsto sulle piattaforme più comuni (lo standard non garantisce che tutti i puntatori abbiano le stesse dimensioni e struttura, ma di solito lo hanno). –

risposta

8

Questo è il codice C di serie

Questo paragrafo del potente standard lo permette (sottolineatura mia):..

(C99, 6.2. 1p7) "I tag struttura, unione e enumerazione hanno portata t hat inizia subito dopo la comparsa del tag in un identificatore di tipo che dichiara il tag. Ogni costante di enumerazione ha un ambito che inizia subito dopo l'apparizione del suo enumeratore di definizione in una lista di elenchi. Qualsiasi altro identificatore ha scope che inizia subito dopo il completamento del suo dichiaratore. "

Per informazioni, si noti che per illustrare l'ultima frase del 6.2.1p7, il libro "The New C standard" di Derek M. Jones utilizza un esempio simile al vostro:

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

Grazie, è solo il risposta che stavo cercando! – Matt

+0

@Matt siete i benvenuti! – ouah

8

Sì a tutte le precedenti. Hai un paio di indicazioni che stai iniziando con lo stesso indirizzo, quindi hanno lo stesso indirizzo e lo stesso indirizzo con cui le hai inizializzate.

Forse più interessante è che x.a punta a se stesso (ovvero, il primo elemento in una struttura è garantito proprio all'inizio della struttura, quindi un puntatore alla struttura, convertito nel tipo di struttura primo elemento, è garantito per puntare a quel primo elemento

+0

Quello che stavo chiedendo era se l'indirizzo di 'x' è disponibile nella clausola di inizializzazione. Inoltre, hai ragione che 'xa' punta alla stessa posizione di se stesso ma il tipo è diverso' xa' è una 'struct foo *' e dovrebbe puntare a una 'struct foo' che non è dello stesso tipo di se stessa . – Matt

+0

@Matt: Sì, l'indirizzo è un valore rvalore (essenzialmente una costante), quindi dal punto di vista del programma, questo non è molto diverso da qualcosa come 'int x = 1234;' –