c - para - poligono en r
¿Por qué deberíamos tipear una estructura tan a menudo en C? (15)
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 un agrupamiento conveniente de una colección de vars para la conveniencia de manejo (K&R, pg127, C prog lang.) Como una sola unidad
C> typedef''ing una estructura 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.
He visto muchos programas que consisten en estructuras como la de abajo.
typedef struct
{
int i;
char k;
} elem;
elem user;
¿Por qué se necesita tan a menudo? ¿Alguna razón específica o área aplicable?
Como dijo Greg Hewgill, typedef significa que ya no tienes que escribir struct
todas partes. Eso no solo ahorra pulsaciones, sino que también puede hacer que el código sea más limpio, ya que proporciona un poco más de 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 "Punto" en su idioma. Que, después de la typedef
, es el caso, supongo.
También tenga en cuenta que si bien su ejemplo (y el mío) omitió nombrar la struct
sí, en realidad nombrarla también es útil cuando desea proporcionar un tipo opaco. Entonces tendrías 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 declaración de struct
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 declaració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 de C muy apreciados en los que este uso de typedef
para ocultar la struct
se considera una mala idea, el kernel de Linux es probablemente el proyecto de este tipo más conocido. Consulte el capítulo 5 del documento The Linux Kernel CodingStyle para ver las palabras enojadas de Linus. :) Mi punto es que el "debería" en la pregunta tal vez no esté escrito en piedra, después de todo.
De un viejo artículo de Dan Saks ( http://www.ddj.com/cpp/184403396?pgno=3 ):
Las reglas del lenguaje C para las estructuras de nombres 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 s que 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, conceptualmente, si no están físicamente separados 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 ámbito. Por ejemplo,
struct s s;
Es una declaración válida que declara la variable s de tipo struct s. Puede que no sea una buena práctica, pero los compiladores de C deben aceptarlo. Nunca he visto una razón de por qué C fue diseñado de esta manera. Siempre he pensado que era un error, pero ahí está.
Muchos programadores (incluido el tuyo de verdad) prefieren pensar en los nombres de estructura como nombres de tipo, por lo que definen un alias para la etiqueta usando typedef. Por ejemplo, definiendo
struct s { ... }; typedef struct s S;
te permite usar S en lugar de estructuras, 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 estructura, unión o definición de 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 acerca de cómo el comportamiento de C ++ de no requerir un typedef
puede causar problemas de ocultación de nombres sutiles. Para evitar estos problemas, es una buena idea typedef
clases y las estructuras en C ++, aunque a primera vista parezca innecesario. En C ++, con typedef
la ocultación del nombre se convierte en un error que el compilador le informa en lugar de una fuente oculta de posibles problemas.
El uso de typedef
evita tener que escribir la struct
cada vez que declara una variable de ese tipo:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
Empecemos con lo básico y avancemos hacia arriba.
Aquí hay un ejemplo de definición de estructura:
struct point
{
int x, y;
};
Aquí el point
nombre 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, tenga en cuenta el último caso anterior; debe escribir el struct point
para declarar Estructuras de ese tipo si decide crear ese tipo en un punto posterior de su código.
Introduzca typedef
. Si pretende crear una nueva Estructura (la Estructura es un tipo de datos personalizado) más adelante en su programa usando el mismo programa, usar 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 utilizar 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 los nombres de tipo de biblioteca estándar.
En el lenguaje de programación ''C'', la palabra clave ''typedef'' se usa para declarar un nuevo nombre para algún objeto (struct, array, function..enum type). Por ejemplo, usaré un ''struct-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 decido usar un tipo de estructura, necesitaré la palabra clave ''estructura'' 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''.
En general, en lenguaje C, struct / union / enum son instrucciones de macro procesadas por el preprocesador en lenguaje C (no confunda con el preprocesador que trata "#include" y otros)
asi que :
struct a
{
int i;
};
struct b
{
struct a;
int i;
int j;
};
La estructura b se gasta como algo así:
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 independientes, redondeo del preprocesador C en un ciclo de declaración que no puede terminar.
typedef son especificadores de tipo, eso significa que solo el compilador C lo procesa y puede hacer lo que quiera para optimizar la implementación del código del ensamblador. Tampoco se gastan miembros de tipo tan estúpidamente como lo hace el preprocesador con estructuras, pero utilizan un algoritmo de construcción de referencia más complejo, por lo que la 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 es completamente funcional. Esta implementación también brinda acceso a la conversión de tipo de compilador y elimina algunos efectos de error cuando la hebra 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 de la clase C ++ que las estructuras solitarias.
Es increíble la cantidad de personas que se equivocan. POR FAVOR, no escriba las estructuras en C, contaminará innecesariamente el espacio de nombres global que normalmente está muy contaminado en programas de C grandes.
Además, las estructuras tipificadas sin un nombre de etiqueta son una causa importante de la imposición innecesaria de relaciones de ordenación entre 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 una definición de este tipo, sin usar typedefs, es posible que una unidad de compilación incluya foo.h para obtener la definición FOO_DEF
. Si no intenta eliminar la referencia al miembro ''bar'' de la estructura foo
, 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 la denominación de las variables coincidentes con el nombre de su etiqueta de estructura.
Si tengo que mantener su código, eliminaré sus estructuras de tipo typedef.
No creo que las declaraciones a futuro sean posibles con typedef. El uso de struct, enum y union permite reenviar declaraciones cuando las dependencias (conocidas) son bidireccionales.
Estilo: el uso de typedef en C ++ tiene bastante sentido. Casi puede ser necesario cuando se trata de plantillas que requieren múltiples parámetros y / o variables. El typedef ayuda a mantener los nombres rectos.
No es así en el lenguaje de programación C. El uso de typedef a menudo no sirve para ocultar el uso de la estructura de datos. Dado que solo se utiliza {struct (6), enum (4), union (5)} número de pulsaciones para declarar un tipo de datos, casi no hay uso para 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 qué tipo es.
Observe cómo se escribe Linux con estricta evitación de este aliasing typedef sin sentido trae. El resultado es un estilo minimalista y limpio.
Otra buena razón para tipear siempre enums y estructuras es el resultado de este problema:
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
¿Nota el error tipográfico en EnumDef en la estructura (Enu u mDef)? Esto se compila sin error (o advertencia) y es (según 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) utilizando la definición anterior EnumDef.
Con un typdef, un tipo similar de error tipográfico hubiera resultado en 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 abogaría por SIEMPRE typedef''ing estructuras y enumeraciones.
No solo para guardar algo de escritura (sin juego de palabras;)), sino porque es más seguro.
Resulta que en C99 typedef es obligatorio. Está desactualizado, pero muchas herramientas (como HackRank) usan c99 como su implementación en C pura. Y se requiere typedef allí.
No estoy diciendo que deban cambiar (quizás tengan dos opciones de C) si el requisito cambia, los que estudiamos para las entrevistas en el sitio serían SOL.
Resulta que hay pros y contras. Una fuente de información útil es el libro seminal "Programación Experto C" ( Capítulo 3 ). Brevemente, en C tiene múltiples espacios de nombres: etiquetas, tipos, nombres de miembros e identificadores . 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. Una etiqueta en el espacio de nombres de la etiqueta y un tipo en el espacio de nombres de tipo. Así que puedes hacer tanto Type myType
como struct Tag myTagType
. Declaraciones como struct Type myType
o Tag myTagType
son ilegales. Además, en una declaración como esta:
typedef Type *Type_ptr;
Definimos un puntero a nuestro tipo. Así que si declaramos:
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
entonces var1
, var2
y myTagType1
son punteros a Tipo pero myTagType2
no.
En el libro mencionado anteriormente, menciona que las estructuras de escritura de tipos no son muy útiles ya que solo evita que el programador escriba la palabra estructura. Sin embargo, tengo una objeción, como muchos otros programadores de C Aunque a veces se vuelve a ofuscar algunos nombres (por eso no es recomendable en bases de código grandes como el kernel) cuando se desea implementar el polimorfismo en C, es muy útil buscar detalles aquí . 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 quieras realizar dicha funcionalidad. En estos casos, las referencias breves son un gran problema, especialmente si emplea la técnica en su código.
Finalmente, el último aspecto con tipos typedef
es la incapacidad de extenderlos, en contraste con las macros. Si por ejemplo, usted tiene:
#define X char[10] or
typedef char Y[10]
entonces puedes declarar
unsigned X x; but not
unsigned Y y;
Realmente no nos preocupamos por esto por las estructuras, ya que no se aplica a los especificadores de almacenamiento ( volatile
and const
).
el nombre que usted (opcionalmente) le da a la estructura se llama el nombre de la etiqueta y, como se ha señalado, no es un tipo en sí mismo. Para llegar al tipo se requiere el prefijo de estructura.
Aparte de GTK +, no estoy seguro de que el tagname se use tan comúnmente como typedef para el tipo struct, por lo que en C ++ se reconoce y puede omitir la palabra clave struct y usar el tagname como nombre de tipo también:
struct MyStruct
{
int i;
};
// The following is legal in C++:
MyStruct obj;
obj.i = 7;
typedef no proporcionará un conjunto co-dependiente de estructuras de datos. 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?
kernel.org/doc/Documentation/CodingStyle Capítulo 5 ofrece grandes ventajas y desventajas (en su mayoría en contra) de usar typedef
.
Por favor no uses cosas como "vps_t".
Es un error usar typedef para estructuras y punteros. Cuando ves 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 el 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 accesorias" no son buenas en sí mismas. La razón por la que los tenemos para cosas como pte_t, etc., es que realmente no hay información accesible de manera portátil allí.
(b) Tipos de enteros claros, donde la abstracción ayuda a evitar confusiones ya sea "int" o "long".
u8 / u16 / u32 son typedefs perfectamente bien, aunque encajan en la categoría (d) mejor que aquí.
¡NOTA! De nuevo, tiene que haber una razón para esto. Si algo está "sin firmar mucho tiempo", entonces no hay razón para hacerlo
typedef unsigned long myflags_t;
pero si hay una razón clara por la cual, bajo ciertas circunstancias, podría ser un "int sin signo" y bajo otras configuraciones podría ser "sin firmar de largo", entonces, adelante, utilice un typedef.
(c) cuando se utiliza disperso para crear literalmente un nuevo tipo para la comprobación de tipos.
(d) Nuevos tipos que son idénticos a los tipos estándar C99, en ciertas circunstancias excepcionales.
Aunque solo llevaría un corto período de tiempo para que los ojos y el cerebro se acostumbraran 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 propio código nuevo.
Al editar el código existente que ya utiliza uno u otro conjunto de tipos, debe ajustarse a las opciones existentes en ese código.
(e) Tipos seguros para su uso en espacio de usuario.
En ciertas estructuras que son visibles para el espacio de usuario, no podemos requerir tipos de C99 y no podemos usar el formulario ''u32'' de arriba. Por lo tanto, utilizamos __u32 y tipos similares en todas las estructuras que se comparten con el espacio de usuario.
Tal vez haya otros casos también, pero la regla básicamente debería ser NUNCA NUNCA use 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.