¿Por qué debemos escribir def una estructura tan a menudo en C?


407

He visto muchos programas que consisten en estructuras como la siguiente

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

¿Por qué se necesita con tanta frecuencia? ¿Alguna razón específica o área aplicable?


14
Respuesta más completa y precisa: stackoverflow.com/questions/612328/…
AbiusX

Tiene desventajas, creo que no puede crear una lista de enlaces con estructura anónima porque la línea struct * ptrdentro de la estructura causará un error
Raghib Ahsan

99
La 'respuesta más completa y precisa' es la diferencia entre struct y typedef struct en C ++ , y existen diferencias significativas entre C y C ++ en esta área que hacen que esa respuesta no sea del todo apropiada para una pregunta sobre C.
Jonathan Leffler

Esta pregunta tiene un duplicado typedef struct vs struct definiciones que también tiene respuestas estelares.
Jonathan Leffler

2
OTOH, kernel.org/doc/html/v4.10/process/coding-style.html nos dice que no deberíamos hacer tales typedefs.
glglgl

Respuestas:


455

Como dijo Greg Hewgill, el typedef significa que ya no tienes que escribir por structtodas partes. Eso no solo ahorra pulsaciones de teclas, sino que también puede hacer que el código sea más limpio, ya que proporciona una pizca más abstracción.

Cosas como

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

se vuelve más limpio cuando no necesita ver la palabra clave "struct" en todo el lugar, parece más como si realmente hubiera un tipo llamado "Point" en su idioma. Lo cual, después del typedef, es el caso, supongo.

También tenga en cuenta que si bien su ejemplo (y el mío) omitió nombrar a struct sí mismo, en realidad nombrarlo también es útil para cuando desea proporcionar un tipo opaco. Entonces tendría un código como este en el encabezado, por ejemplo:

typedef struct Point Point;

Point * point_new(int x, int y);

y luego proporcione la structdefinición en el archivo de implementación:

struct Point
{
  int x, y;
};

Point * point_new(int x, int y)
{
  Point *p;
  if((p = malloc(sizeof *p)) != NULL)
  {
    p->x = x;
    p->y = y;
  }
  return p;
}

En este último caso, no puede devolver el Punto por valor, ya que su definición está oculta para los usuarios del archivo de encabezado. Esta es una técnica utilizada ampliamente en GTK + , por ejemplo.

ACTUALIZACIÓN Tenga en cuenta que también hay proyectos C de gran prestigio en los que este uso de typedefocultar structse considera una mala idea, el kernel de Linux es probablemente el proyecto más conocido. Vea el Capítulo 5 del documento Linux Kernel CodingStyle para las palabras de enojo de Linus. :) Mi punto es que el "debería" en la pregunta quizás no esté escrito en piedra, después de todo.


58
No debe usar identificadores con un guión bajo seguido de una letra mayúscula, están reservados (consulte la sección 7.1.3, párrafo 1). Aunque es poco probable que sea un gran problema, es un comportamiento técnicamente indefinido cuando los usa (7.1.3, párrafo 2).
dreamlax

16
@dreamlax: en caso de que no estuviera claro para los demás, eso solo comienza un identificador con un guión bajo y una mayúscula que no debe hacer; eres libre de usar eso en medio de un identificador.
brianmearns

12
Es interesante que el ejemplo dado aquí (en el que typedef evita el uso de "struct" "en todo el lugar") es en realidad más largo que el mismo código sin typedef, ya que ahorra exactamente un uso de la palabra "struct". La pizca de abstracción obtenida rara vez se compara favorable con la ofuscación adicional.
William Pursell el

77
@Rerito fyi, página 166 del borrador del C99 . Todos los identificadores que comienzan con un guión bajo y una letra mayúscula u otro guión bajo siempre están reservados para cualquier uso. Y todos los identificadores que comienzan con un guión bajo siempre están reservados para su uso como identificadores con alcance de archivo tanto en el espacio de nombre ordinario como en el de etiqueta.
e2-e4

10
Curiosamente, las pautas de codificación del kernel de Linux dicen que deberíamos ser mucho más conservadores sobre el uso de typedefs (sección 5): kernel.org/doc/Documentation/CodingStyle
gsingh2011

206

Es sorprendente cuántas personas se equivocan. POR FAVOR, no escriba las estructuras de definición en C, ya que contamina innecesariamente el espacio de nombres global, que normalmente ya está muy contaminado en los grandes programas de C.

Además, las estructuras typedef'd sin un nombre de etiqueta son una causa importante de la imposición innecesaria de relaciones de orden entre los archivos de encabezado.

Considerar:

#ifndef FOO_H
#define FOO_H 1

#define FOO_DEF (0xDEADBABE)

struct bar; /* forward declaration, defined in bar.h*/

struct foo {
  struct bar *bar;
};

#endif

Con tal definición, sin usar typedefs, es posible que una unidad compiland incluya foo.h para llegar a la FOO_DEFdefinición. Si no intenta desreferenciar al miembro 'bar' de la fooestructura, entonces no será necesario incluir el archivo "bar.h".

Además, dado que los espacios de nombres son diferentes entre los nombres de etiqueta y los nombres de miembros, es posible escribir código muy legible como:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

Como los espacios de nombres están separados, no hay conflicto en nombrar variables que coincidan con su nombre de etiqueta de estructura.

Si tengo que mantener su código, eliminaré sus estructuras typedef'd.


37
Lo que es más sorprendente es que 13 meses después de dar esta respuesta, ¡soy el primero en votarla! typedef'ing structs es uno de los mayores abusos de C, y no tiene cabida en el código bien escrito. typedef es útil para des-ofuscar los tipos de puntero de función contorneados y realmente no sirve para ningún otro propósito útil.
William Pursell

28
Peter van der Linden también presenta un caso contra las estructuras de definición de texto en su libro esclarecedor "Programación experta en C - Secretos profundos en C". La esencia es: QUIERES saber que algo es una estructura o unión, no OCULTARLO.
Jens

34
El estilo de codificación del kernel de Linux prohíbe explícitamente las estructuras de definición de tipos. Capítulo 5: Typedefs: "Es un error usar typedef para estructuras y punteros". kernel.org/doc/Documentation/CodingStyle
jasso

63
¿Qué beneficios, exactamente, proporciona escribir "struct" una y otra vez? Y hablando de contaminación, ¿por qué querrías tener una estructura y una función / variable / typedef con el mismo nombre en un espacio de nombres global (a menos que sea un typedef para esa misma función)? El patrón seguro es usar typedef struct X { ... } X. De esa manera, puede usar el formulario corto Xpara abordar la estructura en cualquier lugar donde esté disponible la definición, pero aún puede declarar hacia adelante y usar struct Xcuando lo desee.
Pavel Minaev

77
Personalmente muy raramente si alguna vez uso typedef, no diría que otras personas no deberían usarlo, simplemente no es mi estilo. Me gusta ver una estructura antes de un tipo de variable, así que sé de inmediato que es una estructura. El argumento más fácil de escribir es un poco aburrido, tener variables que son una sola letra también es más fácil de escribir, también con autocompletaciones de lo difícil que es escribir struct hoy en día en cualquier lugar.
Nathan Day

138

De un artículo antiguo de Dan Saks ( http://www.ddj.com/cpp/184403396?pgno=3 ):


Las reglas del lenguaje C para nombrar estructuras son un poco excéntricas, pero son bastante inofensivas. Sin embargo, cuando se extiende a las clases en C ++, esas mismas reglas abren pequeñas grietas para que los errores puedan rastrearse.

En C, el nombre aparece en

struct s
    {
    ...
    };

es una etiqueta Un nombre de etiqueta no es un nombre de tipo. Dada la definición anterior, declaraciones como

s x;    /* error in C */
s *p;   /* error in C */

son errores en C. Debes escribirlos como

struct s x;     /* OK */
struct s *p;    /* OK */

Los nombres de uniones y enumeraciones también son etiquetas en lugar de tipos.

En C, las etiquetas son distintas de todos los demás nombres (para funciones, tipos, variables y constantes de enumeración). Los compiladores de C mantienen etiquetas en una tabla de símbolos que es conceptualmente, si no físicamente, separada de la tabla que contiene todos los demás nombres. Por lo tanto, es posible que un programa en C tenga una etiqueta y otro nombre con la misma ortografía en el mismo alcance. Por ejemplo,

struct s s;

es una declaración válida que declara variables s de tipo struct s. Puede que no sea una buena práctica, pero los compiladores de C deben aceptarlo. Nunca he visto una justificación de por qué C fue diseñado de esta manera. Siempre he pensado que fue un error, pero ahí está.

Muchos programadores (incluido el suyo de verdad) prefieren pensar en los nombres de estructura como nombres de tipo, por lo que definen un alias para la etiqueta utilizando un typedef. Por ejemplo, definiendo

struct s
    {
    ...
    };
typedef struct s S;

le permite usar S en lugar de struct s, como en

S x;
S *p;

Un programa no puede usar S como el nombre de un tipo y una variable (o función o constante de enumeración):

S S;    // error

Esto es bueno.

El nombre de la etiqueta en una definición de estructura, unión o enumeración es opcional. Muchos programadores pliegan la definición de estructura en typedef y prescinden de la etiqueta por completo, como en:

typedef struct
    {
    ...
    } S;

El artículo vinculado también tiene una discusión sobre cómo el comportamiento de C ++ de no requerir un typedefpuede causar problemas sutiles para ocultar nombres. Para evitar estos problemas, también es una buena idea para typedefsus clases y estructuras en C ++, aunque a primera vista parezca innecesario. En C ++, con el typedefnombre oculto se convierte en un error que el compilador le informa en lugar de una fuente oculta de posibles problemas.


2
Un ejemplo de dónde el nombre de etiqueta es el mismo que un nombre sin etiqueta es en el programa (POSIX o Unix) con la int stat(const char *restrict path, struct stat *restrict buf)función. Allí tiene una función staten el espacio de nombre ordinario y struct staten el espacio de nombre de etiqueta.
Jonathan Leffler

2
su declaración, SS; // error .... ES INCORRECTO Funciona bien. Me refiero a su afirmación de que "no podemos tener el mismo nombre para la etiqueta typedef y var" es INCORRECTO ... por favor verifique
eRaisedToX

63

Usar a typedefevita tener que escribir structcada vez que declaras una variable de ese tipo:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct

2
ok no estamos teniendo ese problema en C ++. Entonces, ¿por qué nadie elimina ese problema técnico del compilador de C y lo hace igual que en C ++? Ok C ++ tiene algunas áreas de aplicación diferentes y, por lo tanto, tiene las características avanzadas. Pero no podemos heredar algunas de ellas en C sin cambiar el C original?
Manoj duda el

44
Manoj, el nombre de la etiqueta ("struct foo") es necesario cuando necesita definir una estructura que se haga referencia a sí misma. por ejemplo, el puntero "siguiente" en una lista vinculada. Más concretamente, el compilador implementa el estándar, y eso es lo que el estándar dice que haga.
Michael Carman

41
No es una falla en el compilador de C, es parte del diseño. Cambiaron eso para C ++, lo que creo que facilita las cosas, pero eso no significa que el comportamiento de C sea incorrecto.
Herms

55
desafortunadamente, muchos 'programadores' definen una estructura y luego la escriben con un nombre 'no relacionado' (como struct myStruct ...; typedef struct myStruct susan *; en casi todos los casos, una typedef no conduce a nada más que saturar el código, ocultando la definición real de una variable / parámetro, y lleva a error a todos, incluido el escritor original del código.
user3629249

1
@ user3629249 Estoy de acuerdo con usted en que el estilo de programación mencionado es horrible, pero esta no es una razón para denigrar typedefestructuras en general. También podrías hacer typedef struct foo foo;. Por supuesto, la structpalabra clave no se requiere más de lo que puede ser una pista útil de que el alias de tipo que vemos es un alias para una estructura pero no es malo en general. Considere también un caso en el que el identificador del alias tipo resultante de typedefindica que es un alias para una estructura, Fe: typedef struct foo foo_struct;.
RobertS apoya a Monica Cellio

38

Otra buena razón para escribir siempre enumeraciones y estructuras resulta de este problema:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Observe el error tipográfico en EnumDef en la estructura (Enu u mDef)? Esto se compila sin error (o advertencia) y es (dependiendo de la interpretación literal del Estándar C) correcto. El problema es que acabo de crear una nueva definición de enumeración (vacía) dentro de mi estructura. No estoy (según lo previsto) usando la definición anterior EnumDef.

Con un error tipográfico similar, los errores tipográficos habrían provocado errores de compilación al usar un tipo desconocido:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */

Yo recomendaría SIEMPRE estructuras y enumeraciones de tipografía.

No solo para guardar algo de escritura (sin juego de palabras;)), sino porque es más seguro.


1
Peor aún, su error tipográfico podría coincidir con una etiqueta diferente. En el caso de una estructura, esto podría provocar que todo el programa se compile correctamente y tenga un comportamiento indefinido en tiempo de ejecución.
MM

3
esta definición: 'typedef {FIRST_ITEM, SECOND_ITEM} EnumDef;' no define una enumeración. He escrito cientos de programas enormes y tuve la mala fortuna de realizar tareas de mantenimiento en programas que otros han escrito. De la mano dura de la experiencia, usar typedef en una estructura solo conduce a problemas. Esperemos que el programador no esté tan discapacitado que tenga problemas para escribir una definición completa cuando declara una instancia de estructura. C no es básico, por lo que escribir algunos caracteres más no es perjudicial para el funcionamiento del programa.
user3629249

2
Para aquellos que sienten cierta aversión a escribir más que el número mínimo absoluto de caracteres, les sugiero que se unan a algún grupo que intente escribir aplicaciones con el número mínimo de pulsaciones de teclas. Simplemente no use su nueva 'habilidad' en un entorno de trabajo, especialmente en un entorno de trabajo que realiza rigurosamente revisiones por pares
usuario3629249

Tenga en cuenta que, por lo general, se desaconseja su uso enumcomo tipo, ya que muchos compiladores emiten advertencias extrañas cuando los usan 'incorrectos'. Por ejemplo, inicializar un enuma 0 podría dar una advertencia de 'constante constante que no está en enumeración'. Declarar hacia adelante enumtampoco está permitido. Uno debería usar int(o unsigned int) en su lugar.
aaaa

55
Ese ejemplo no se compila, ni esperaría que lo hiciera. Compilación Debug / test.o test.c: 10: 17: error: el campo tiene un tipo incompleto 'enum EnuumDef' enum EnuumDef MyEnum; ^ test.c: 10: 8: nota: declaración directa de 'enum EnuumDef' enum EnuumDef MyEnum; ^ 1 error generado. gnuc, con std = c99.
natersoz

30

El Capítulo 5 del estilo de codificación del kernel de Linux ofrece excelentes ventajas y desventajas (principalmente contras) de uso typedef.

Por favor, no use cosas como "vps_t".

Es un error usar typedef para estructuras y punteros. Cuando veas un

vps_t a;

en la fuente, ¿qué significa?

Por el contrario, si dice

struct virtual_container *a;

en realidad puedes decir qué es "a".

Mucha gente piensa que typedefs "ayuda a la legibilidad". No tan. Son útiles solo para:

(a) objetos totalmente opacos (donde typedef se usa activamente para ocultar lo que es el objeto).

Ejemplo: "pte_t", etc., objetos opacos a los que solo puede acceder utilizando las funciones de acceso adecuadas.

¡NOTA! La opacidad y las "funciones de acceso" no son buenas en sí mismas. La razón por la que los tenemos para cosas como pte_t etc es que realmente es absolutamente cero información de manera portátil puede acceder allí.

(b) Tipos enteros claros, donde la abstracción ayuda a evitar confusiones si es "int" o "largo".

u8 / u16 / u32 son tipos de letra perfectamente precisos, aunque encajan en la categoría (d) mejor que aquí.

¡NOTA! Nuevamente, debe haber una razón para esto. Si algo es "sin firmar por mucho tiempo", entonces no hay razón para hacerlo

typedef unsigned long myflags_t;

pero si hay una razón clara de por qué bajo ciertas circunstancias podría ser un "unsigned int" y bajo otras configuraciones podría ser "unsigned long", entonces, por supuesto, siga adelante y use typedef.

(c) cuando usa disperso para crear literalmente un nuevo tipo para la verificación de tipo.

(d) Nuevos tipos que son idénticos a los tipos C99 estándar, en ciertas circunstancias excepcionales.

Aunque solo tomaría poco tiempo para que los ojos y el cerebro se acostumbren a los tipos estándar como 'uint32_t', algunas personas se oponen a su uso de todos modos.

Por lo tanto, los tipos específicos de Linux 'u8 / u16 / u32 / u64' y sus equivalentes firmados que son idénticos a los tipos estándar están permitidos, aunque no son obligatorios en el nuevo código propio.

Al editar el código existente que ya usa uno u otro conjunto de tipos, debe ajustarse a las opciones existentes en ese código.

(e) Tipos seguros para usar en el espacio de usuario.

En ciertas estructuras que son visibles para el espacio de usuario, no podemos requerir tipos C99 y no podemos usar el formulario 'u32' anterior. Por lo tanto, usamos __u32 y tipos similares en todas las estructuras que se comparten con el espacio de usuario.

Tal vez también haya otros casos, pero la regla debería ser NUNCA utilizar un typedef a menos que pueda coincidir claramente con una de esas reglas.

En general, un puntero o una estructura que tenga elementos a los que se pueda acceder directamente de manera razonable nunca debe ser un typedef.


44
"La opacidad y las" funciones de acceso "no son buenas en sí mismas". ¿Alguien puede explicar por qué? Creo que ocultar información y encapsular sería una muy buena idea.
Yawar

55
@Yawar Acabo de leer este documento y tuve exactamente el mismo pensamiento. Claro, C no está orientado a objetos, pero la abstracción sigue siendo una cosa.
Baldrickk

12

Resulta que hay pros y contras. Una fuente útil de información es el libro seminal "Programación Expert C" ( Capítulo 3 ). Brevemente, en C tiene múltiples espacios de nombres: etiquetas, tipos, nombres de miembros e identificadores . typedefintroduce un alias para un tipo y lo ubica en el espacio de nombres de la etiqueta. A saber,

typedef struct Tag{
...members...
}Type;

define dos cosas Una etiqueta en el espacio de nombres de etiqueta y un tipo en el espacio de nombres de tipo. Por lo que puede hacer ambas cosas Type myTypey struct Tag myTagType. Declaraciones como struct Type myTypeo Tag myTagTypeson ilegales. Además, en una declaración como esta:

typedef Type *Type_ptr;

definimos un puntero a nuestro tipo. Entonces si declaramos:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

entonces var1, var2y myTagType1son punteros a Tipo pero myTagType2no.

En el libro mencionado anteriormente, menciona que las estructuras de definición de texto no son muy útiles, ya que solo evita que el programador escriba la palabra struct. Sin embargo, tengo una objeción, como muchos otros programadores de C. Aunque a veces se vuelve para ofuscar algunos nombres (es por eso que no es aconsejable en bases de código grandes como el núcleo) cuando se quiere implementar el polimorfismo en C, ayuda mucho mirar aquí para más detalles . Ejemplo:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

tu puedes hacer:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

Por lo tanto, puede acceder a un miembro externo ( flags) mediante la estructura interna ( MyPipe) a través de la conversión. Para mí es menos confuso lanzar todo el tipo que hacer(struct MyWriter_ *) s; cada vez que desee realizar dicha funcionalidad. En estos casos, las referencias breves son importantes, especialmente si emplea la técnica en su código.

Finalmente, el último aspecto con los typedeftipos ed es la incapacidad de extenderlos, en contraste con las macros. Si, por ejemplo, tienes:

#define X char[10] or
typedef char Y[10]

entonces puedes declarar

unsigned X x; but not
unsigned Y y;

Realmente no nos interesan las estructuras porque no se aplica a los especificadores de almacenamiento ( volatiley const).


1
MyPipe *s; MyWriter *self = (MyWriter *) s;y acabas de romper el alias estricto.
Jonathon Reinhart

@JonathonReinhart Sería ilustrativo mencionar cómo esto se puede evitar, por ejemplo, cómo el elenco-feliz enormemente GTK + funciona alrededor de ella: bugzilla.gnome.org/show_bug.cgi?id=140722 / mail.gnome.org/archives/gtk -devel-list / 2004-April / msg00196.html
underscore_d

"typedef introduce un alias para un tipo y lo ubica en el espacio de nombres de la etiqueta. A saber" typedef struct Tag{ ...members... }Type; "define dos cosas" no tiene mucho sentido. si typedef define etiquetas, entonces 'Tipo' aquí también debería ser una etiqueta. La verdad es que la definición define 2 etiquetas y 1 tipo (o tipos 2 y 1 etiqueta no está seguro.): struct Tag, TagY Type. struct TagDefinitivamente es un tipo. Tages una etiqueta pero la confusión es si Typees una etiqueta o un tipo
Qwertyzw

12

No creo que las declaraciones futuras sean posibles con typedef. El uso de struct, enum y union permite reenviar declaraciones cuando las dependencias (sabe) son bidireccionales.

Estilo: el uso de typedef en C ++ tiene bastante sentido. Casi puede ser necesario cuando se trata de plantillas que requieren parámetros múltiples y / o variables. El typedef ayuda a mantener el nombre directo.

No es así en el lenguaje de programación C. El uso de typedef con mayor frecuencia no tiene otro propósito que ofuscar el uso de la estructura de datos. Dado que solo se utilizan {struct (6), enum (4), union (5)} número de pulsaciones de teclas para declarar un tipo de datos, casi no se utiliza el aliasing de la estructura. ¿Es ese tipo de datos una unión o una estructura? El uso de la declaración directa no tipificada le permite saber de inmediato de qué tipo es.

Observe cómo se escribe Linux evitando estrictamente este aliasing sin sentido que typedef trae. El resultado es un estilo minimalista y limpio.


10
Clean no se structrepetiría en todas partes ... Typedef crea nuevos tipos. ¿Que usas? Tipos No nos importa si es una estructura, unión o enumeración, es por eso que la definimos.
GManNickG

13
No, qué importa si se trata de una estructura o unión, frente a una enumeración o algún tipo atómico. No puede forzar una estructura a un número entero o a un puntero (ni a ningún otro tipo, de hecho), que es todo lo que a veces tiene que almacenar en algún contexto. Tener las palabras clave 'struct' o 'union' alrededor mejora la localidad del razonamiento. Nadie dice que necesitas saber qué hay dentro de la estructura.
Bernd Jendrissek

1
@BerndJendrissek: Las estructuras y las uniones son diferentes de otros tipos, pero ¿debería importarle el código del cliente cuál de esas dos cosas (estructura o unión) es algo así como un FILE?
supercat

44
@supercat FILE es un buen uso de typedef. Creo que typedef se usa en exceso , no es que sea una mala característica del lenguaje. En mi humilde opinión, usar typedef para todo es el olor del código de "sobregeneralidad especulativa". Observe que declara variables como FILE * foo, nunca como FILE foo. Para mí, esto importa.
Bernd Jendrissek

2
@supercat: "Si las variables de identificación de archivos fueran de tipo FILE en lugar de FILE * ..." ¡Pero esa es exactamente la ambigüedad que permiten typedefs! Solo estamos acostumbrados a tomar un ARCHIVO * para no preocuparnos por eso, pero cada vez que agrega typedef está introduciendo otro poco de sobrecarga cognitiva: ¿esta API quiere foo_t args o foo_t *? Llevar explícitamente la 'estructura' mejora la localidad del razonamiento, aunque a costa de unos pocos caracteres más por definición de función.
Bernd Jendrissek

4

Comencemos con lo básico y avancemos.

Aquí hay un ejemplo de definición de estructura:

struct point
  {
    int x, y;
  };

Aqui el nombre point es opcional.

Una estructura puede declararse durante su definición o después.

Declarando durante la definición

struct point
  {
    int x, y;
  } first_point, second_point;

Declarando después de la definición

struct point
  {
    int x, y;
  };
struct point first_point, second_point;

Ahora, observe cuidadosamente el último caso anterior; necesitas escribirstruct point para declarar estructuras de ese tipo si decide crear ese tipo más adelante en su código.

Introduzca typedef. Si tiene la intención de crear una nueva Estructura (la Estructura es un tipo de datos personalizado) más adelante en su programa usando el mismo modelo, usarlo typedefdurante su definición podría ser una buena idea ya que puede guardar algo de escritura en adelante.

typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;

Una palabra de precaución al nombrar su tipo personalizado

Nada le impide usar el sufijo _t al final de su nombre de tipo personalizado, pero el estándar POSIX se reserva el uso del sufijo _t para denotar nombres de tipo de biblioteca estándar.


3

el nombre que (opcionalmente) le da a la estructura se llama nombre de etiqueta y, como se ha señalado, no es un tipo en sí mismo. Para llegar al tipo requiere el prefijo struct.

Dejando a un lado GTK +, no estoy seguro de que el nombre de etiqueta se use de manera tan común como typedef para el tipo de estructura, por lo que en C ++ eso se reconoce y puede omitir la palabra clave de estructura y usar el nombre de etiqueta como nombre de tipo también:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;


1

typedef no proporcionará un conjunto de estructuras de datos co-dependientes. Esto no se puede hacer con typdef:

struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};

Por supuesto, siempre puedes agregar:

typedef struct foo foo_t;
typedef struct bar bar_t;

¿Cuál es exactamente el punto de eso?


1

A> a typdef ayuda en el significado y la documentación de un programa al permitir la creación de sinónimos más significativos para los tipos de datos . Además, ayudan a parametrizar un programa contra problemas de portabilidad (K&R, pg147, C prog lang).

B> una estructura define un tipo . Structs permite la agrupación conveniente de una colección de vars para la comodidad de manejo (K&R, pg127, C prog lang.) Como una sola unidad

C> typedef'ing a struct se explica en A arriba.

D> Para mí, las estructuras son tipos o contenedores personalizados o colecciones o espacios de nombres o tipos complejos, mientras que un typdef es solo un medio para crear más apodos.


0

Resulta que en C99 se requiere typedef. Está desactualizado, pero muchas herramientas (ala HackRank) usan c99 como su implementación pura de C. Y typedef se requiere allí.

No estoy diciendo que deberían cambiar (tal vez tener dos opciones de C) si el requisito cambiara, aquellos de nosotros que estudiemos para entrevistas en el sitio sería SOL.


2
"Resulta que en C99 typedefes obligatorio". ¿Qué quieres decir?
Julien Lopez el

La pregunta es sobre C, no C++. En Ctypedefs son 'obligatorios' (y probablemente siempre lo serán). 'Obligatorio' como en, no podrá declarar una variable Point varName;y hacer que el tipo sea struct Point;sin sin typedef struct Point Point;.
aaaa

0

En el lenguaje de programación 'C', la palabra clave 'typedef' se usa para declarar un nuevo nombre para algún objeto (estructura, matriz, función ... tipo de enumeración). Por ejemplo, usaré una 'estructura-s'. En 'C' a menudo declaramos una 'estructura' fuera de la función 'principal'. Por ejemplo:

struct complex{ int real_part, img_part }COMPLEX;

main(){

 struct KOMPLEKS number; // number type is now a struct type
 number.real_part = 3;
 number.img_part = -1;
 printf("Number: %d.%d i \n",number.real_part, number.img_part);

}

Cada vez que decida usar un tipo de estructura necesitaré esta palabra clave 'struct' algo '' nombre '.' Typedef 'simplemente cambiará el nombre de ese tipo y puedo usar ese nuevo nombre en mi programa cada vez que lo desee. Entonces nuestro código será:

typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.

main(){

COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);

}

Si tiene algún objeto local (estructura, matriz, valioso) que se utilizará en todo su programa, simplemente puede darle un nombre usando un 'typedef'.


-2

En absoluto, en lenguaje C, struct / union / enum son macroinstrucciones procesadas por el preprocesador de lenguaje C (no se confunda con el preprocesador que trata "#include" y otros)

entonces :

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

struct b se gasta de la siguiente manera:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

y así, en tiempo de compilación evoluciona en la pila como algo así como: b: int ai int i int j

por eso también es difícil tener estructuras autorreferenciales, el preprocesador C se redondea en un ciclo de declaración que no puede terminar.

typedef son type specifier, eso significa que solo el compilador C lo procesa y puede hacer lo que quiera para optimizar la implementación del código ensamblador. Tampoco gasta miembro de tipo par estúpidamente como lo hace un procesador previo con estructuras, pero usa un algoritmo de construcción de referencia más complejo, por lo que construcción como:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

Está permitido y totalmente funcional. Esta implementación también da acceso a la conversión de tipo compilador y elimina algunos efectos de error cuando el hilo de ejecución abandona el campo de aplicación de las funciones de inicialización.

Esto significa que en C typedefs están más cerca como clase de C ++ que en estructuras solitarias.


3
No es difícil tener estructuras autorreferenciales en absoluto. struct foo {struct foo * siguiente; cosa int; }
Bernd Jendrissek

44
...¿qué? Diciendo preprocesador para describir la resolución de structsy typedefS es bastante malo, pero el resto de su escritura es tan confuso que me resulta difícil conseguir ningún mensaje de ella. Sin embargo, una cosa que puedo decir es que su idea de que un no- typedefd structno puede ser declarado hacia adelante o utilizado como un miembro opaco (puntero) es totalmente falso. En su primer ejemplo, struct bpuede contener trivialmente a struct a *, no typedefrequerido. Las afirmaciones de que structson simples piezas tontas de macroexpansión, y que typedefles dan nuevos poderes revolucionarios, son dolorosamente incorrectas
subrayado_d
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.