2009-11-29 32 views
10

El siguiente código se compila en un compilador de C++.Estructuras anidadas

#include<cstdio> 
int main() 
{ 
struct xx 
{ 
    int x; 
    struct yy 
    { 
     char s; 
     struct xx *p; 
    }; 
    struct yy *q; 
}; 

¿Habrá alguna diferencia de comportamiento al compilar con un compilador de C?
es decir, ¿habría algún error de compilación?

+0

¿Cuál es el error –

+0

I don'? t tiene un compilador C. Pero vi este ejemplo en un texto C diciendo que esto dará lugar a un error de compilación. – Ankur

Respuesta

0

Bueno, cstdio debe ser referido como stdio.h. En cuanto a la estructura, struct-keyword no es necesaria en C++.

Realmente no define miembros de estructura, sino miembros de puntero, por lo que parece plausible que funcione en ambos casos.

0

Acabo de probar que con ligeras modificaciones y el compilador gcc

struct xx { 
     int x; 
     struct yy { char s; struct xx *p; }; 
     struct yy *q; 
}; 

int main() { return 0; } 

compilar con gcc

$ gcc test.c 
test.c:3: warning: declaration does not declare anything 

I compila pero da una advertencia. Como mi C está demasiado oxidada, no puedo decir nada más.

0

Basado en mi breve investigación y el mensaje de error publicado por Otto, parece que C no permite que las estructuras sean contenedores de espacio de nombres de uso general como las clases y estructuras C++ (naturalmente, porque C ni siquiera admite clases) Así que no se puede anidar definiciones de la estructura en C. Usted tendría que declarar la estructura interna fuera de la declaración de la estructura exterior de la siguiente manera:

struct yy 
{ 
     char s; 
     struct xx *p; 
}; 
struct xx 
{ 
    int x; 
    struct yy *q; 
}; 

veo que las estructuras de referencia cruzada entre sí. Así que si esto es posible en C, puede que tenga que declarar la validez de la estructura después con una línea como:

struct xx; 

(ambos por encima de otras declaraciones).

+0

estructuras mutuamente recursivos son posibles en C. se hacen simplemente como usted dice, con una declaración adelantada. –

4

Éstos son algunos cambios (gracias a AndreyT):

Obviamente hay que cambiar los encabezados para hacer esta compilación. Pero incluso entonces, esto parece no ser el estándar C como AndreyT señalado. No obstante, algunos compiladores como gcc seguirán compilando como se esperaba y solo emitirán una advertencia. Del mismo modo, Microsoft no parece interpretar la norma demasiado estricta:

"declaraciones de estructuras también se pueden especificar sin declarador cuando son miembros de otra estructura o unión"

Para que sea norma C tienes que convertir tu declaración "struct yy" en una definición. Entonces su código será válido en C y en C++. Para ilustrar lo que está sucediendo, lo reescribí en una forma, en mi opinión, más comprensible y agregué una pequeña prueba sobre lo que está sucediendo.

#include<stdio.h> 
#include<stdlib.h> 

typedef struct xx xx; 
typedef struct yy yy; 

struct yy{ char s; xx *p;}; 

struct xx{ int x; yy *q;}; 

int main(){ 
    xx test; 
    test.q = (yy*)malloc(sizeof(yy)); 
    test.q->s = 'a'; 
    test.q->p = (xx*)malloc(sizeof(xx)); 
    test.q->p->x = 1; 
    test.q->p->q = (yy*)malloc(sizeof(yy)); 
    test.q->p->q->s = 'b'; 
    printf("s: %c\n", test.q->s); 
    printf("x: %d\n", test.q->p->x); 
    printf("s: %c\n", test.q->p->q->s); 
    return 0; 
} 

Se puede ver fácilmente, que tiene una estructura yy con un puntero a xx xx y la estructura tiene un puntero a aa.Esto es equivalente a la que se puede escribir como seguido en ANSI-C:

#include<stdio.h> 
#include<stdlib.h> 

int main(){ 
    struct xx{ 
     int x; 
     struct yy{ 
        char s; 
        struct xx *p; 
      } *q; 
      /*Here is the change to your example. You cannot have a structur 
       without a declactor inside of another structur! 
       Your version might due to compiler extensions still work*/ 
    }; 
    struct xx test; 
    test.q = (struct yy*)malloc(sizeof(struct yy)); 
    test.q->s = 'a'; 
    test.q->p = (struct xx*)malloc(sizeof(struct xx)); 
    test.q->p->x = 1; 
    test.q->p->q = (struct yy*)malloc(sizeof(struct yy)); 
    test.q->p->q->s = 'b'; 
    printf("s: %c\n", test.q->s); 
    printf("x: %d\n", test.q->p->x); 
    printf("s: %c\n", test.q->p->q->s); 
    return 0; 
} 

Compilé con gcc y las siguientes opciones:

gcc -ansi -pedantic -Wall -W -Wshadow -Wcast-qual -Wwrite-strings test.c -o 

Ambas variantes tendrán la misma salida

s: a 
x: 1 
s: b 

Ahora, si quiere hacer lo mismo en C++, su estructura no tiene que cambiar, pero para usar la estructura interna debe llamar al operador de resolución del alcance (: :) como sigue:

test.q = (xx::yy*)malloc(sizeof(xx::yy)); 
test.q->s = 'a'; 
test.q->p = (xx*)malloc(sizeof(xx)); 
test.q->p->x = 1; 
test.q->p->q = (xx::yy*)malloc(sizeof(xx::yy)); 
test.q->p->q->s = 'b'; 
printf("s: %c\n", test.q->s); 
printf("x: %d\n", test.q->p->x); 
printf("s: %c\n", test.q->p->q->s); 
+0

Bueno, su segundo ejemplo "equivalente" hace una modificación importante que hace que sea válida C. la modificación es la declaración de 'miembro q'. el código original no era válido C, su modificación se. – AnT

+0

AndreyT hizo este comentario antes de editar mi respuesta. – Lucas

16

El código en tu post es obviamente incompleta, sólo declaraciones, por lo que es difícil decir algo concluyente.

En diferencia obvia es que en C++ del tipo struct interior será un miembro de tipo struct exterior, mientras que en el lenguaje C ambos tipos struct serán miembros de la misma alcance (que encierra). (Por cierto, ¿era su intención de declarar de forma local en main?).

En otras palabras, en C++ el código que sigue tendría que hacer referencia a las estructuras como xx y xx::yy, mientras que en C serían simplemente xx y yy. Esto significa que el código se vería aún más diferente para C y C++ y si va a compilar en C++, no sería compilar en C y viceversa.

Agregado: C El lenguaje prohíbe declarar tipos de estructuras dentro de otras estructuras sin declarar un miembro de ese tipo. Entonces, la declaración struct yy es ilegal en C y producirá un mensaje de diagnóstico del compilador. Si usted quiere que su código para que sea legal en C y C++, habría que combinar la declaración struct yy con algún miembro de la declaración de datos. En el caso que podría ser puntero q:

struct xx { 
     int x; 
     struct yy { 
       char s; 
       struct xx *p; 
     } *q; 
}; 

Lo anterior es legal en C y C++ (teniendo en cuenta las diferencias que he explicado anteriormente), pero su declaración original no es legal en C.

+0

Buena observación sobre C++. Pero, ¿estás seguro de que la declaración estructural es ilegal? Compilará bien con gcc excepto la advertencia y también produce el comportamiento esperado. – Lucas

+1

Sí, estoy seguro. La gramática del lenguaje C establece explícitamente que las "entrañas" de una "estructura" deben consistir completamente en * declaradores *. Una declaración 'struct' sin una declaración de miembro no es un * declarador *. GCC lo acepta como una extensión. GCC tiene muchas extensiones.GCC no es bueno para "intentar" con el propósito de verificar la legalidad del código. Comeau Online es mucho mejor para ese propósito. – AnT

+0

Gracias por la aclaración. Cambié mi respuesta de acuerdo a tus comentarios. Lamentablemente, solo recibo un voto positivo. – Lucas

1

C no le permite anidar una declaración de tipo dentro de una definición de función. Además, para eliminar la advertencia de "no declara nada, debe fusionar las declaraciones de tipo struct yy y miembro q A continuación se compila con gcc con advertencias máximo en:.

struct xx 
{ 
     int x; 
     struct yy 
     { 
       char s; 
       struct xx *p; 
     } *q; 
}; 

int main() 
{ 
    return 0; 
}