c++ - tipos - typedef struct uso
¿Cuál es el significado de `struct X typedef` contra` typedef struct X`? (5)
¡Realmente puedes poner todos los especificadores de declaración en el orden que quieras! Las posiciones de los punteros *
y el declarador real (la variable o el nuevo nombre del tipo) son importantes, pero todo lo que typedef
int
unsigned
const
static
etc. puede tener cualquier orden.
Si miras la gramática oficial de C, solo dice:
declaration:
declaration-specifiers init-declarator-list ;
Los declaration-specifiers
son todos los especificadores de clases de almacenamiento ( typedef
, extern
, etc.), los especificadores de tipo (el tipo real, como int
o struct X
), los calificadores ( const
y volatile
) y algunos otros menos comunes. Su orden no es importante. La segunda parte es la lista init-declarator-list
, y es la variable o el nuevo nombre de tipo (en el caso de un typedef), cualquier *
carácter, la inicialización de la variable ( int x = 3
) y más. El orden de las cosas en la parte del declarador es importante, pero no el orden en los especificadores de la declaración.
Tengo el siguiente código (de trabajo) en una base de código existente, que se usa en el archivo de inclusión que se comparte entre C y C ++, compilando en MSVC (2010) y Windows DDK:
struct X {
USHORT x;
} typedef X, *PX;
Y:
enum MY_ENUM {
enum_item_1,
enum_item_2
} typedef MY_ENUM;
Hasta donde yo sé, la definición correcta debería verse así:
typedef struct {
USHORT x;
} X, *PX;
¿Hay algún propósito para tener el siguiente formulario? ¿Me estoy perdiendo de algo?
Ambos tienen el mismo significado. Ambas formas son válidas:
typedef <existing_type> <new_type>
<existing_type> typedef <new_type>
Puede typedef
la estructura anterior de cualquier forma:
struct X {
USHORT x;
}typedef X, *PX; // <existing_type> typedef <new_type>
o
typedef struct {
USHORT x;
} X, *PX; // typedef <existing_type> <new_type>
Como dijeron otros, typedef
es un especificador de clase de almacenamiento y, como con otros especificadores de clase de almacenamiento, también se le permite poner el especificador entre el tipo y el declarador.
Si bien esto es válido y también es un formulario que debe evitarse ya que C lo marcó como una característica obsoleta:
(C11, 6.11.5p1) "La ubicación de un especificador de clase de almacenamiento que no sea al comienzo de los especificadores de declaración en una declaración es una característica obsoleta".
El hecho de que tanto typedef <type> <alias>
como <type> typedef <alias>
sean válidos simplemente proviene de la definición de la gramática del lenguaje.
typedef
se clasifica como un especificador de clase de almacenamiento (como static
, auto
), y el tipo en sí mismo se conoce como type-specifier . De las definiciones de sintaxis en la sección 6.7 de la norma, verá que estas son libres de ser intercambiadas:
declaration:
declaration-specifiers init-declarator-list ;
declaration-specifiers:
storage-class-specifier declaration-specifiers
type-specifier declaration-specifiers
type-qualifier declaration-specifiers
function-specifier declaration-specifiers
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator
declarator = initializer
(Nótese, por supuesto, que esto es igualmente cierto para las estructuras y para las no-estructuras, lo que significa que el double typedef trouble;
es también válido).
Descargo de responsabilidad: esta no es una respuesta técnica sino práctica. Consulte las otras respuestas para asuntos técnicos. Esta respuesta dice obstinada y subjetiva, pero por favor ten paciencia conmigo mientras trato de explicar el panorama completo.
struct
es una bestia extraña porque lo que pones entre el corchete de cierre }
y el punto y coma ;
se refiere al contenido dentro o antes de esos corchetes. Sé por qué es así, y gramaticalmente tiene sentido, pero personalmente me resulta muy contrario a la intuición ya que las llaves generalmente significan alcance:
Contra-ejemplos intuitivos:
// declares a variable named `foo` of unnamed struct type.
struct {
int x, y;
} foo;
foo.x = 1;
// declares a type named `Foo` of unnamed struct type
struct {
int x, y;
} typedef Foo;
Foo foo2;
foo2.x = 2;
// declares a type named `Baz` of the struct named `Bar`
struct Bar {
int x, y;
} typedef Baz;
// note the ''struct'' keyword to actually use the type ''Bar''
struct Bar bar;
bar.x = 3;
Baz baz;
baz.x = 4;
Hay tantas cosas sutiles que pueden salir mal con la sintaxis densa de struct
s y typedef
s si se usan así. Como se muestra a continuación, es muy fácil declarar una variable en lugar de un tipo por accidente. El compilador solo tiene una ayuda limitada porque casi todas las combinaciones son gramaticalmente correctas. Simplemente no significan necesariamente lo que intentas expresar. Es un pozo de desesperación .
Ejemplos incorrectos:
// mixed up variable and type declaration
struct foo {
int x, y;
} Foo;
// declares a type ''foo'' instead of a variable
typedef struct Foo {
int x, y;
} foo;
// useless typedef but compiles fine
typedef struct Foo {
int x, y;
};
// compiler error
typedef Foo struct {
int x, y;
};
Por razones de legibilidad y mantenimiento, prefiero declarar todo por separado y nunca colocar nada detrás del corchete de cierre. El costo de las líneas de código adicionales se ve superado fácilmente por la sintaxis intuitiva. Yo sostengo que este enfoque hace que sea fácil hacer las cosas correctas y molesto hacer las cosas incorrectas .
Ejemplos intuitivos:
// declares a struct named ''TVector2''
struct TVector2 {
float x, y;
};
// declares a type named ''Vector2'' to get rid of the ''struct'' keyword
// note that I really never use ''TVector2'' afterwards
typedef struct TVector2 Vector2;
Vector2 v, w;
v.x = 0;
v.y = 1;