16

quería ver si podía inicializar una variable global para apuntar a sí mismo:Inicializando datos circulares en C. ¿Este código C es válido según cualquier estándar?

#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; 
} 

Este código se compila y se ejecuta como se esperaba con gcc (todo de impresión de tres puntos de forma idéntica).

Quiero saber:

  1. Esto es confiable?
  2. ¿Es este estándar?
  3. ¿Es esto portátil?

EDIT: Solo para aclarar, estoy cuestionando la disponibilidad de la dirección de x en su propia inicializador.

+0

Hay un problema: '% p' espera un' void * ', pero los argumentos son' struct foo * 's. –

+0

@DanielFischer Does not C permite conversiones silenciosas desde y hacia' void * 'desde cualquier otro puntero para permitir funciones como 'malloc' para trabajar sin conversiones explícitas? – Matt

+1

Lo hace, pero solo en la asignación. Cuando pasa cosas a' printf', no ocurre tal conversión (varargs, sin verificación de tipo en absoluto). Así 'printf' obtiene 'struct foo *' s, pero la cadena de formato requiere 'void *'. Tu compilador debería advertirte sobre eso (si subes el nivel de advertencia). Pedante, eso es incluso un comportamiento indefinido, aunque funcionará según lo previsto en la mayoría de las plataformas comunes (el estándar no garantiza que todos los punteros tengan el mismo tamaño y estructura, pero por lo general lo tienen). –

Respuesta

8

Este es el código estándar de C

Este párrafo del poderoso norma permite que (el énfasis es mío):..

(C99, 6.2. 1p7) "Las etiquetas de estructura, unión y enumeración tienen alcance t El sombrero comienza justo después de la aparición de la etiqueta en un especificador de tipo que declara la etiqueta. Cada constante de enumeración tiene un alcance que comienza justo después de la aparición de su enumerador de definición en una lista de enumerador. Cualquier otro identificador tiene alcance que comienza justo después de la finalización de su declarador. "

Para obtener más información, tenga en cuenta que para ilustrar la última frase del 6.2.1p7, el libro "The New Standard C" por Derek M. Jones usa un ejemplo similar a la suya:

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

Gracias, eso es solo el ¡respuesta que estaba buscando! – Matt

+0

@Matt ¡De nada! – ouah

8

Sí a todo lo anterior. Tiene un par de punteros que está inicializando con la misma dirección, por lo que tienen la misma dirección, y eso es lo mismo que la dirección con la que los inicializó.

Quizás más interesante, x.a también se garantiza que apunta a sí mismo (es decir, se garantiza que el primer elemento de una estructura está en el comienzo de la estructura, por lo que un puntero a la estructura, convertido al tipo de primer elemento, se garantiza que señalar que el primer elemento de

+0

Lo que estaba cuestionando era si la dirección de 'x' está disponible en la cláusula de inicialización. Además, tienes razón en que 'xa' apunta a la misma ubicación que ella, pero el tipo es diferente' xa' es 'struct foo *' y debe apuntar a una 'struct foo' que no es del mismo tipo que ella . – Matt

+0

@Matt: Sí, la dirección es un valor r (esencialmente, una constante), así que desde el punto de vista del programa, esto no es muy diferente de algo como 'int x = 1234;' –