¿Por qué deberíamos tipear una estructura con tanta frecuencia en C?

12 minutos de lectura

avatar de usuario
Manoj Dudas

He visto muchos programas que consisten en estructuras como la siguiente

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

elem user;

¿Por qué se necesita tan a menudo? ¿Algún motivo específico o área aplicable?

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

    – AbiusX

    17 de marzo de 2011 a las 2:14

  • Tiene desventajas. Creo que no puedes crear una lista de enlaces con una estructura anónima porque la línea struct * ptr dentro de la estructura causará un error

    – Raghib Ahsan

    1 de febrero de 2016 a las 17:40


  • La ‘respuesta más completa y precisa’ es Diferencia entre estructura y estructura typedef 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

    5 de junio de 2016 a las 22:21

  • Esta pregunta tiene una estructura de typedef duplicada frente a definiciones de estructura que también tiene respuestas estelares.

    –Jonathan Leffler

    5 de junio de 2016 a las 22:25

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

    – glglgl

    27 de marzo de 2018 a las 15:52

avatar de usuario
Jerry Hicks

Es increíble cuántas personas se equivocan en esto. POR FAVOR, no escriba estructuras def en C, ya que contamina innecesariamente el espacio de nombres global que, por lo general, ya está muy contaminado en programas C grandes.

Además, las estructuras typedef’d sin un nombre de etiqueta son una de las principales causas 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 de compilación incluya foo.h para llegar al FOO_DEF definición. Si no intenta desreferenciar el miembro ‘bar’ del foo struct entonces no habrá necesidad de incluir el archivo “bar.h”.

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

struct foo *foo;

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

Dado que 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.

  • Lo que es más sorprendente es que 13 meses después de que se da esta respuesta, ¡soy el primero en votarla! La definición de tipos de estructuras es uno de los mayores abusos de C, y no tiene cabida en un código bien escrito. typedef es útil para desofuscar tipos de punteros de función intrincados y realmente no sirve para ningún otro propósito útil.

    – William Pursell

    25 de enero de 2012 a las 14:04

  • Peter van der Linden también presenta un caso en contra de las estructuras typedefing en su esclarecedor libro “Expert C Programming – Deep C Secrets”. La esencia es: QUIERES saber que algo es una estructura o unión, no OCULTARLO.

    – Jens

    14 de marzo de 2012 a las 10:31

  • 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

    – jaso

    9 de diciembre de 2012 a las 22:39


  • ¿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 puedes usar la forma abreviada X para abordar la estructura en cualquier lugar donde la definición esté disponible, pero aún puede declarar y usar struct X cuando se desee.

    – Pavel Minaev

    20 de marzo de 2013 a las 7:18

  • Personalmente, rara 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 para saber de inmediato que es una estructura. El argumento más fácil de escribir es un poco cojo, tener variables que son una sola letra también es más fácil de escribir, también con las autocompletaciones, lo difícil que es escribir struct hoy en día en cualquier lugar.

    – Día de Nathan

    1 de junio de 2013 a las 10:26


  • Un ejemplo de donde el nombre de la etiqueta es el mismo que un nombre sin etiqueta es en el programa (POSIX o Unix) con el int stat(const char *restrict path, struct stat *restrict buf) función. ahi tienes una funcion stat en el espacio de nombres ordinario y struct stat en el espacio del nombre de la etiqueta.

    –Jonathan Leffler

    5 de junio de 2016 a las 22:02

  • su declaración, SS; // error…. ES INCORRECTO Funciona bien. Me refiero a que su declaración de que “no podemos tener el mismo nombre para la etiqueta typedef y var” es INCORRECTA … por favor verifique

    – eRaisedToX

    3 de agosto de 2016 a las 7:24


Usando un typedef evita tener que escribir struct cada vez que declaras una variable de ese tipo:

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

  • ok, no estamos teniendo ese problema en C++. Entonces, ¿por qué nadie elimina esa falla del compilador de C y lo hace igual que en C++? Bueno, C++ tiene algunas áreas de aplicación diferentes y, por lo tanto, tiene características avanzadas. Pero, ¿no podemos heredar algunas de ellas en C sin cambiar el C originales?

    – Manoj Dudas

    31 de octubre de 2008 a las 12:03

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

    –Michael Carman

    31 de octubre de 2008 a las 13:05

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

    – Hermes

    31 de octubre de 2008 a las 19:36

  • desafortunadamente, muchos ‘programadores’ definen una estructura y luego la escriben con algún nombre ‘no relacionado’ (como struct myStruct …; typedef struct myStruct susan*; En casi todos los casos, typedef conduce a nada más que abarrotar el código, ocultando la definición real de una variable/parámetro, y engaña a todos, incluido el escritor original del código.

    – usuario3629249

    28 mayo 2015 a las 20:50

  • @user3629249 Estoy de acuerdo contigo en que el estilo de programación mencionado es horrible, pero esto no es motivo para denigrar typedefestructuras de construcción en general. también podrías hacer typedef struct foo foo;. por supuesto el struct La palabra clave no se requiere más, lo que puede ser una pista útil de que el tipo de alias que miramos es un alias para una estructura, pero no está mal en general. Considere también un caso donde el identificador del alias de tipo resultante de typedef indica que es un alias para una estructura, fe: typedef struct foo foo_struct;.

    – RobertS apoya a Mónica Cellio

    10 de febrero de 2020 a las 19:38


avatar de usuario
Yun

Estilo de codificación del kernel de Linux El Capítulo 5 brinda grandes ventajas y desventajas (principalmente desventajas) de usar typedef.

Por favor, no use cosas como “vps_t”.

Es un error para usar typedef para estructuras y punteros. cuando ves un

vps_t a;

en la fuente, ¿qué significa?

En cambio, 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 el typedef se usa activamente para esconder cuál 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 accesorias” no son buenas en sí mismas. La razón por la que los tenemos para cosas como pte_t, etc. es que realmente hay absolutamente cero información accesible de forma portátil allí.

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

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

¡NOTA! Una vez más, tiene que haber un razón para esto. Si algo es “largo sin firmar”, entonces no hay razón para hacerlo

typedef unsigned long myflags_t;

pero si hay una razón clara por la que, en determinadas circunstancias, podría ser un “int sin firmar” y, en otras configuraciones, podría ser “largo sin firmar”, entonces, por todos los medios, continúe y use un typedef.

(c) cuando usas sparse para crear literalmente un nuevo type para verificación de tipo.

d) Nuevos tipos idénticos a los tipos C99 estándar, en determinadas circunstancias excepcionales.

Aunque los ojos y el cerebro tardarían poco tiempo en acostumbrarse a los tipos estándar como ‘uint32_t’, algunas personas se oponen a su uso de todos modos.

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

Al editar 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 del 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 básicamente debería ser NUNCA NUNCA usar un typedef a menos que pueda coincidir claramente con una de esas reglas.

En general, un puntero o una estructura que tiene elementos a los que se puede acceder razonablemente de forma directa debe nunca ser un typedef.

  • ok, no estamos teniendo ese problema en C++. Entonces, ¿por qué nadie elimina esa falla del compilador de C y lo hace igual que en C++? Bueno, C++ tiene algunas áreas de aplicación diferentes y, por lo tanto, tiene características avanzadas. Pero, ¿no podemos heredar algunas de ellas en C sin cambiar el C originales?

    – Manoj Dudas

    31 de octubre de 2008 a las 12:03

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

    –Michael Carman

    31 de octubre de 2008 a las 13:05

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

    – Hermes

    31 de octubre de 2008 a las 19:36

  • desafortunadamente, muchos ‘programadores’ definen una estructura y luego la escriben con algún nombre ‘no relacionado’ (como struct myStruct …; typedef struct myStruct susan*; En casi todos los casos, typedef conduce a nada más que abarrotar el código, ocultando la definición real de una variable/parámetro, y engaña a todos, incluido el escritor original del código.

    – usuario3629249

    28 mayo 2015 a las 20:50

  • @user3629249 Estoy de acuerdo contigo en que el estilo de programación mencionado es horrible, pero esto no es motivo para denigrar typedefestructuras de construcción en general. también podrías hacer typedef struct foo foo;. por supuesto el struct La palabra clave no se requiere más, lo que puede ser una pista útil de que el tipo de alias que miramos es un alias para una estructura, pero no está mal en general. Considere también un caso donde el identificador del alias de tipo resultante de typedef indica que es un alias para una estructura, fe: typedef struct foo foo_struct;.

    – RobertS apoya a Mónica Cellio

    10 de febrero de 2020 a las 19:38


Comencemos con lo básico y avancemos.

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

struct point
  {
    int x, y;
  };

Aquí el nombre point es opcional.

Una Estructura puede ser declarada durante su definición o después.

Declarar durante la definición

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

Declarar después de la definición

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

Ahora, observe cuidadosamente el último caso anterior; tienes que escribir struct point para declarar estructuras de ese tipo si decide crear ese tipo en un punto posterior de su código.

Ingresar typedef. Si tiene la intención de crear una nueva Estructura (Estructura es un tipo de datos personalizado) en un momento posterior en su programa usando el mismo plano, usando typedef durante su definición puede ser una buena idea, ya que puede ahorrar algo de escritura en el futuro.

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 reserva el uso del sufijo _t para indicar nombres de tipo de biblioteca estándar.

  • Él typedef point { ... } Points no es una muy buena idea. Desde el nombre point y Points tener demasiada diferencia. Cuando alguien tiene que reenviar declarar el struct para un puntero, el nombre diferente es un problema, especialmente cuando está en una biblioteca que puede cambiar. Si utiliza typedef usar el mismo nombre o tener una regla clara sobre cómo convertir el nombre del struct nombre a la typedef nombre.

    – 12431234123412341234123

    7 de septiembre de 2020 a las 9:17

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad