2009-10-21 17 views
34

Ayer encontré un código de inicialización de estructuras que me lanzó a un bucle. He aquí un ejemplo:C struct initialization using labels. Funciona, pero ¿cómo?

typedef struct { int first; int second; } TEST_STRUCT; 
void testFunc() { 
    TEST_STRUCT test = { 
     second: 2, 
     first: 1 
    }; 
    printf("test.first=%d test.second=%d\n", test.first, test.second); 
} 

sorprendente (para mí), aquí está la salida:

-> testFunc 
test.first=1 test.second=2 

Como se puede ver, la estructura se ha inicializado correctamente. No sabía que las declaraciones etiquetadas pudieran usarse así. He visto varias otras maneras de hacer la inicialización de estructuras, pero no encontré ningún ejemplo de este tipo de inicialización de estructuras en ninguna de las preguntas frecuentes en línea de C. ¿Alguien sabe cómo/por qué esto funciona?

Respuesta

25

Aquí es la sección del manual de gcc lo que explica la sintaxis de inicializadores designados para ambas estructuras y matrices:

En un inicializador estructura, especifique el nombre de un campo para inicializar con '.fieldname = 'antes del valor del elemento. Por ejemplo, dada la siguiente estructura,

struct point { int x, y; }; 

la siguiente inicialización

struct point p = { .y = yvalue, .x = xvalue }; 

es equivalente a

struct point p = { xvalue, yvalue }; 

Otra sintaxis que tiene el mismo significado, obsoleto desde GCC 2.5, es 'nombre de campo:', como se muestra aquí:

struct point p = { y: yvalue, x: xvalue }; 

La página relevante se puede encontrar en here.

Su compilador debe tener documentación similar.

+2

excelente, que la documentación que explica claramente la sintaxis: Otra sintaxis que tiene el mismo significado, obsoleto desde GCC 2.5, es 'nombre de campo:', como se muestra aquí: struct punto p = {y: yvalue, x: xvalue}; –

+1

@AndrewCottrell, esta sintaxis de "nombre de campo:" parece tan natural (y preferible) para mí, ¿alguna idea de por qué debería considerarse obsoleta? – rick

+1

@rick la sintaxis "fieldname:" es una extensión gcc y nunca ha sido parte de ningún estándar ISO C. – sigjuice

5

No son realmente "declaraciones etiquetadas", sino una forma de dar valores iniciales a los campos nombrados en la estructura.

gcc da una advertencia de "uso obsoleto del inicializador designado con ':'", y en C99 en su lugar debe escribir:

TEST_STRUCT test = { 
     .second = 2, 
     .first = 1 
    }; 
32

Estos son ni etiquetas ni los campos de bits.

Esta es una sintaxis para inicializar los miembros de la estructura que data de los días anteriores a C99. No está estandarizado, pero está disponible en, por ejemplo, gcc.

typedef struct { int y; int x; } POINT; 
POINT p = { x: 1, y: 17 }; 

En C99, la sintaxis para la inicialización de miembros de la estructura específica se ha introducido por primera vez en una norma, pero se ve un poco diferente:

typedef struct { int y; int x; } POINT; 
POINT p = { .x = 1, .y = 17 }; 
+0

Sí, estaba al tanto del formato de inicializador designado. Lamentablemente, ese formato no es compatible con C++. (No en mis pruebas de todos modos.) Gracias por la respuesta. Es bueno saber que esto no está estandarizado. –

+6

@ Andrew nunca se ha dicho nada acerca de C++ en su pregunta – horseyguy

3

que la sintaxis no se define por la Norma C . Sección 6.7.8 Initialization dice

  designation: 
       designator-list = 
     designator-list: 
       designator 
       designator-list designator 
     designator: 
       [ constant-expression ] 
       . identifier 

Si su compilador acepta una designación con dos puntos y sin un mensaje de diagnóstico que significa que el compilador no es (o está configurado para no ser) Cumplimiento de normas.

9

Sí, como se señaló anteriormente, estos son los inicializadores designados, que son estándar C, aunque debe cambiar a usar períodos en lugar de dos puntos. Y como usted nota, la mayoría de los libros que hay por ahí todavía están en algún lugar alrededor de 1984 en su sintaxis y no los mencionan. Datos más divertidos:

- Al utilizar los inicializadores designados, todo lo no especificado se inicializa en cero. Esto ayuda con excepcionalmente grandes estructuras, por ejemplo:

typedef struct { 
    double a, b, c, d, e; 
    char label[100]; 
} too_many_type; 

too_many_type tm = {.a = 1, .e = 2, .b=1.5}; 
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5); 
assert(!strlen(label)); 

--también, puede utilizar la forma literal compuesto a utilizar esta forma en una línea de no inicialización, por ejemplo:

too_many_type tm2; 
tm2 = (too_many_type) {.a = 3, .e=6}; 

Estos son realmente excelentes características, y son compatibles con cada compilador de C que se me ocurra, ya que es el estándar. Es una pena que no sean tan conocidos.

+1

La sintaxis alternativa (que usa dos puntos) parece tan natural y preferible para mí, ¿podría aclarar por qué deberíamos usar periodos en lugar de dos puntos? – rick