¿Las estructuras no definen los tipos?

Acabo de comenzar a aprender C con una formación profesional en Java y algo de conocimiento de C ++ (si no demasiado), y me sorprendió que esto no funcionara en C:

struct Point { int x; int y; }; Point p; px = 0; py = 0; 

Parece que tengo que declarar p usando struct Point como el tipo o usando typedef . ¿Este código funciona en C99? ¿O es esto una “cosa de C ++”?

Por lo que sé, tampoco debería funcionar sin un typedef en C99 (ya que esta es simplemente la forma en que funciona C), pero funciona en C ++ como una struct en C ++ es solo una class con todos los miembros públicos de forma predeterminada.

No, una estructura no define un nuevo tipo. Lo que necesitas es:

 typedef struct { int x; int y; } Point; 

Ahora Point es un nuevo tipo que puedes usar:

 Point p; px = 0; py = 0; 

struct Point es el tipo al igual que union Foo sería un tipo. Puede usar typedef para typedef un alias a otro nombre – typedef struct Point Point; .

En C no hay confusión entre

 struct Point { int x; int y; }; 

y

 union Point { int x; int y; }; 

que son dos tipos diferentes llamados struct Point y union Point respectivamente.

El estándar C99 sección 6.7.2.1 establece:

6 Los especificadores de estructura y unión tienen la misma forma. Las palabras clave struct y union indican que el tipo que se está especificando es, respectivamente, un tipo de estructura o un tipo de unión.

7 La presencia de una estructura-statement-lista en una estructura-o-unión-especificador declara un nuevo tipo, dentro de una unidad de traducción.

Así que de manera más inequívoca declara un tipo. La syntax para los nombres de tipo en C se da en las secciones 6.7.6 e incluye la lista de calificador-especificador de 6.7.2, que toma la forma de struct-or-union identifier de struct-or-union identifier .

¿Este código funciona en C99? ¿O es esto una “cosa de C ++”?

No, C99 no decide promover tipos de estructura sobre tipos de enumeración y tipos de unión con el mismo nombre. Es una “cosa de C ++”, ya que la estructura y las clases son casi lo mismo en C ++, y las clases son importantes para C ++.

Asi que…

 Point a tag struct Point a type typedef struct { . . . } Point_t; Point_t a type 

A menudo veo un por qué? Escrito entre líneas. Después de todo, parece perfectamente razonable decir simplemente el Point x; Entonces, ¿por qué no puedes?

A medida que sucede, las implementaciones tempranas de C establecieron un espacio de nombres separado para las tags frente a otros identificadores. En realidad, hay 4 espacios de nombres 1 . Una vez que el lenguaje se definió de esta manera, no fue posible permitir que la etiqueta de estructura se usara como un tipo, porque entonces todo el código existente con colisiones de nombres entre identificadores y tags ordinarios se convertiría repentinamente en un error.


1. Los 4 espacios de nombre son:
– nombres de tags (desambiguados por la syntax de la statement y uso de la etiqueta);
– las tags de estructuras, uniones y enumeraciones (desambiguadas al seguir cualquiera) de las palabras clave struct, union o enum);
– los miembros de estructuras o sindicatos; cada estructura o unión tiene un espacio de nombres separado para sus miembros (desambiguado por el tipo de expresión utilizada para acceder al miembro a través del operador .o ->);
– todos los demás identificadores, denominados identificadores ordinarios (declarados en declaradores ordinarios o como constantes de enumeración)

No funciona en C99, es una cosa de C ++. Tienes que decir struct Point o usar typedef en C.

En C, las estructuras pueden tener dos tipos de nombres: un nombre de etiqueta y un nombre de tipo. Un nombre de etiqueta solo se puede usar si está prefijado con struct, como:

 struct mytag { int a; } struct mytag mystruct; 

A typedef le permite definir un nombre de etiqueta y un nombre de tipo. El nombre de tipo se puede usar sin un prefijo de estructura:

 typedef struct mytag { int a; } mytype; mytype mystruct; // No struct required 

Las estructuras no son tipos. Puede crear un punto desde una estructura de la siguiente manera:

 struct Point p; px = 0; py = 0; 

Si desea utilizar una estructura como un tipo, debe teclearla. Esto funciona tanto en C como en C ++:

 typedef struct _point { int x; int y; } Point; 

Sin embargo, siempre asigne un nombre a su estructura, si tiene que reenviar, declare que puede tener punteros a una estructura del mismo tipo o dependencias circulares.

Así es como funciona C En C tienes que decir:

 typedef struct Point { int x; int y; } Point; 

Y luego tendrás un tipo llamado Point que hace lo que quieres.

En C ++ basta con definirlo como lo hiciste.

Primero necesitas hacer de Point un tipo como:

 typedef struct Point { int x; int y; } Point; 

Esto le permite usar Point como tipo, o struct Point

Es decir:

 Point *p; sizeof(struct Point); 

Algunas personas prefieren que el nombre de la estructura sea diferente del tipo que se está creando, como por ejemplo:

 typedef struct _point { ... } Point; 

Te encontrarás con ambos. El último ejemplo me dice que no debería usar struct _point , no está destinado a ser expuesto, excepto como el tipo Point .