typedef es una palabra clave reservada en los lenguajes de programación C y C ++ . Se utiliza para crear un nombre adicional ( alias ) para otro tipo de datos , pero no crea un nuevo tipo, [1] excepto en el caso oscuro de un typedef calificado de un tipo de matriz donde los calificadores typedef se transfieren al elemento de matriz tipo. [2] Como tal, a menudo se usa para simplificar la sintaxis de declarar estructuras de datos complejas que consisten en tipos de estructura y unión , pero es tan común en proporcionar nombres de tipos descriptivos específicos paratipos de datos enteros de diferentes longitudes .
Sintaxis
La sintaxis de la declaración typedef es: [3]
typedef
declaración de tipo ;
El nombre del nuevo alias de tipo sigue la misma sintaxis que declara cualquier otro identificador de C, por lo tanto, en forma más detallada:
typedef
identificador de definición de tipo
En la biblioteca estándar de C y en las especificaciones POSIX, el identificador para la definición de typedef a menudo tiene el sufijo _t
, como en size_t y time_t . Esto se practica en otros sistemas de codificación, aunque POSIX reserva explícitamente esta práctica para los tipos de datos POSIX .
Ejemplos de
typedef int length ;
Esto crea el tipo length
como sinónimo del tipo int
.
Uso de documentación
Una declaración typedef puede usarse como documentación indicando el significado de una variable dentro del contexto de programación, por ejemplo, puede incluir la expresión de una unidad de medida o conteos. Las declaraciones genéricas,
int current_speed ; int high_score ;void felicitar ( int your_score ) { if ( your_score > high_score ) { // ... } }
puede expresarse declarando tipos específicos de contexto:
typedef int km_per_hour ; puntos int typedef ; // `km_per_hour` es sinónimo de` int` aquí, y por lo tanto, el compilador trata // nuestras nuevas variables como enteros. km_per_hour current_speed ; puntos high_score ;void felicitar ( señala your_score ) { if ( your_score > high_score ) { // ... } }
Ambas secciones de código se ejecutan de manera idéntica. Sin embargo, el uso de declaraciones typedef en el segundo bloque de código deja en claro que las dos variables, aunque representan el mismo tipo de datos int
, almacenan datos diferentes o incompatibles. La definición de congratulate()
de your_score
indica al programador que current_speed
(o cualquier otra variable no declarada como a points
) no debe pasarse como argumento. Esto no sería tan evidente si ambos fueran declarados como variables de int
tipo de datos. Sin embargo, la indicación es solo para el programador ; el compilador de C / C ++ considera que ambas variables son de tipo int
y no marca advertencias de discrepancia de tipos o errores para tipos de argumentos "incorrectos" congratulate(points your_score)
en el fragmento de código a continuación:
void foo () { km_per_hour km100 = 100 ; felicitar ( km100 ); }
Simplificación de tipos
Se puede usar una typedef para simplificar la declaración de un tipo compuesto ( estructura , unión ) o tipo de puntero . [4] Por ejemplo,
struct MyStruct { int data1 ; char data2 ; };
Esto define el tipo de datos struct MyStruct
. Una declaración de variable de este tipo en C también requiere la palabra clave struct
, pero puede omitirse en C ++:
struct MyStruct a ;
Una declaración typedef elimina el requisito de especificar struct
en C. Por ejemplo, la declaración
typedef struct MyStruct newtype ;
se reduce a:
newtype a ;
La declaración de estructura y typedef también se pueden combinar en una sola declaración:
typedef struct MyStruct { int data1 ; char data2 ; } newtype ;
O puede usarse de la siguiente manera:
typedef struct { int data1 ; char data2 ; } newtype ;
En C ++ , en contraste con C, las palabras clave struct
, class
y enum
son opcionales en las declaraciones de variables que están separados de las definiciones, siempre y cuando no hay ambigüedad a otro identificador:
struct MyStruct x ; MyStruct y ;
Como tal, MyStruct
se puede usar donde sea que newtype
se pueda usar. Sin embargo, lo contrario no es cierto; por ejemplo, MyStruct
no se pueden nombrar los métodos constructores de newtype
.
Un ejemplo notorio en el que incluso C ++ necesita la struct
palabra clave es la llamada al sistema de estadísticas POSIX que usa una estructura del mismo nombre en sus argumentos:
int stat ( const char * nombre de archivo , struct stat * buf ) { // ... }
Aquí, tanto C como C ++ necesitan la struct
palabra clave en la definición del parámetro.
Punteros
El typedef se puede utilizar para definir un nuevo tipo de puntero.
typedef int * intptr ;intptr ptr ;// Igual que: // int * ptr;
intptr
es un nuevo alias con el tipo de puntero int *
. La definición, intptr ptr;
define una variable ptr
con el tipo int *
. Entonces, ptr
es un puntero que puede apuntar a una variable de tipo int
.
El uso de typedef para definir un nuevo tipo de puntero a veces puede generar confusión. Por ejemplo:
typedef int * intptr ;// Tanto 'cliff' como 'allen' son de tipo int *. acantilado intptr , allen ; // 'cliff2' es de tipo int *, pero 'allen2' es de tipo int **. intptr cliff2 , * allen2 ;// Igual que: // intptr cliff2; // intptr * allen2;
Arriba, intptr cliff, allen;
significa definir 2 variables con int*
tipo para ambas. Esto se debe a que un tipo definido por typedef es un tipo, no una expansión. En otras palabras, intptr
cuál es el int*
tipo, decora tanto cliff
y allen
. Porque intptr cliff2, *allen2;
, el intptr
tipo decora el cliff2
y *allen2
. Entonces, intptr cliff2, *allen2;
es equivalente a 2 definiciones separadas, intptr cliff2;
y intptr *allen2
. intptr *allen2
significa que allen2
es un puntero que apunta a una memoria con int*
tipo. En breve, allen2
tiene el tipo int**
,.
Estructuras y punteros de estructura
Typedefs también puede simplificar definiciones o declaraciones para tipos de punteros de estructura . Considera esto:
struct Node { int datos ; struct Node * nextptr ; };
Usando typedef, el código anterior se puede reescribir así:
typedef struct Node Node ;struct Node { int datos ; Nodo * nextptr ; };
En C, uno puede declarar múltiples variables del mismo tipo en una sola declaración, incluso mezclando estructura con puntero o no puntero. Sin embargo, sería necesario anteponer un asterisco a cada variable para designarla como un puntero. A continuación, un programador podría suponer que de errptr
hecho era un Node *
, pero un error tipográfico significa que errptr
es un Node
. Esto puede provocar errores de sintaxis sutiles.
struct Node * startptr , * endptr , * curptr , * prevptr , errptr , * refptr ;
Al definir typedef Node *
, se asegura que todas las variables son tipos de puntero de estructura, o digamos, que cada variable es un tipo de puntero que apunta a un tipo de estructura .
typedef struct Node * NodePtr ;NodePtr startptr , endptr , curptr , prevptr , errptr , refptr ;
Punteros de función
int do_math ( float arg1 , int arg2 ) { return arg2 ; }int call_a_func ( int ( * call_this ) ( float , int )) { int salida = call_this ( 5.5 , 7 ); salida de retorno ; }int final_result = call_a_func ( & do_math );
El código anterior se puede reescribir con especificaciones typedef:
typedef int ( * MathFunc ) ( flotante , int );int do_math ( float arg1 , int arg2 ) { return arg2 ; }int call_a_func ( MathFunc call_this ) { int salida = call_this ( 5.5 , 7 ); salida de retorno ; }int final_result = call_a_func ( & do_math );
Aquí MathFunc
está el nuevo alias para el tipo. A MathFunc
es un puntero a una función que devuelve un número entero y toma como argumentos un flotante seguido de un número entero.
Cuando una función devuelve un puntero de función , puede ser aún más confuso sin typedef. El siguiente es el prototipo de función de la señal (3) de FreeBSD :
void ( * señal ( int sig , void ( * func ) ( int ))) ( int );
La declaración de función anterior es críptica ya que no muestra claramente qué acepta la función como argumentos, o el tipo que devuelve. Un programador novato puede incluso asumir que la función acepta un solo int
como argumento y no devuelve nada, pero en realidad también necesita un puntero de función y devuelve otro puntero de función. Se puede escribir de forma más limpia:
typedef void ( * sighandler_t ) ( int );sighandler_t señal ( int sig , sighandler_t func );
Matrices
También se puede utilizar typedef para simplificar la definición de tipos de matriz. Por ejemplo,
typedef char arrType [ 6 ];arrType arr = { 1 , 2 , 3 , 4 , 5 , 6 }; arrType * pArr ;// Igual que: // char arr [6] = {1, 2, 3, 4, 5, 6}; // char (* pArr) [6];
Aquí arrType
está el nuevo alias para el char[6]
tipo, que es un tipo de matriz con 6 elementos. Porque arrType *pArr;
, pArr
es un puntero que apunta a la memoria del char[6]
tipo.
Tipo de moldes
Una typedef se crea usando la sintaxis de definición de tipos, pero se puede usar como si se creara usando la sintaxis de conversión de tipos . ( La conversión de tipos cambia un tipo de datos). Por ejemplo, en cada línea después de la primera línea de:
// `funcptr` es un puntero a una función que toma un` doble` y devuelve un `int`. typedef int ( * funcptr ) ( doble );// Válido tanto en C como en C ++. funcptr x = ( funcptr ) NULL ;// Solo válido en C ++. funcptr y = funcptr ( NULL ); funcptr z = static_cast < funcptr > ( NULL );
funcptr
se usa en el lado izquierdo para declarar una variable y se usa en el lado derecho para emitir un valor. Por lo tanto, los programadores que no deseen descubrir cómo convertir la sintaxis de definición en sintaxis de conversión de tipos pueden utilizar typedef.
Sin typedef, generalmente no es posible usar la sintaxis de definición y la sintaxis de conversión de manera intercambiable. Por ejemplo:
vacío * p = NULO ;// Esto es legal. int ( * x ) ( doble ) = ( int ( * ) ( doble )) p ;// El lado izquierdo no es legal. int ( * ) ( doble ) y = ( int ( * ) ( doble )) p ;// El lado derecho no es legal. int ( * z ) ( doble ) = ( int ( * p ) ( doble ));
Uso en C ++
En C ++, los nombres de los tipos pueden ser complejos y typedef proporciona un mecanismo para asignar un nombre simple al tipo.
std :: vector < std :: par < std :: string , int >> valores ;para ( std :: vector < std :: par < std :: string , int >> :: const_iterator i = valores . begin (); i ! = valores . end (); ++ i ) { std :: par < std :: cadena , int > const & t = * i ; // ... }
y
typedef std :: par < std :: string , int > valor_t ; typedef std :: vector < valor_t > valores_t ;valores_t valores ;for ( valores_t :: const_iterator i = valores . begin (); i ! = valores . end (); ++ i ) { valor_t const & t = * i ; // ... }
C ++ 11 introdujo la posibilidad de expresar typedefs con en using
lugar de typedef
. Por ejemplo, las dos definiciones de tipo anteriores podrían escribirse de forma equivalente como
usando value_t = std :: pair < std :: string , int > ; usando valores_t = std :: vector < valor_t > ;
Usar con plantillas
C ++ 03 no proporciona typedefs con plantilla . Por ejemplo, para tener stringpair
representan std::pair<:string t="">,>
para cada tipo T
uno no se puede utilizar:
plantilla < typename T > typedef std :: pair < std :: string , T > stringpair < T > ; // No funciona
Sin embargo, si uno está dispuesto a aceptar stringpair
en lugar de stringpair
, entonces es posible lograr el resultado deseado a través de una typedef dentro de una clase o estructura con plantilla que de otro modo no se usaría:
template < typename T > class stringpair { private : // Evita la creación de instancias de `stringpair `. stringpair (); public : // Hacer que `stringpair :: type` represente` std :: pair `. typedef std :: pair < std :: string , T > tipo ; };// Declara una variable de tipo `std :: pair `. stringpair < int > :: tipo my_pair_of_string_and_int ;
En C ++ 11 , las definiciones de tipo con plantilla se agregan con la siguiente sintaxis, que requiere la using
palabra clave en lugar de la typedef
palabra clave. (Consulte los alias de las plantillas ). [5]
plantilla < typename T > usando stringpair = std :: pair < std :: string , T > ;// Declara una variable de tipo `std :: pair `. stringpair < int > my_pair_of_string_and_int ;
Otros idiomas
En SystemVerilog , typedef se comporta exactamente como lo hace en C y C ++. [6]
En muchos lenguajes funcionales de tipo estático, como Haskell , Miranda , OCaml , etc., se pueden definir sinónimos de tipo , que son los mismos que typedefs en C.Un ejemplo en Haskell:
tipo PairOfInts = ( Int , Int )
Este ejemplo ha definido un sinónimo de tipo PairOfInts
como un tipo entero.
En Seed7, la definición de un tipo constante se usa para introducir un sinónimo para un tipo:
tipo const: myVector es un entero de matriz;
En Swift , uno usa la typealias
palabra clave para crear un typedef:
typealias PairOfInts = ( Int , Int )
C # contiene una característica que es similar a typedef o la using
sintaxis de C ++. [7] [5]
usando newType = global :: System . Tiempo de ejecución . Interoperabilidad . Mariscal ; usando otherType = Enums . MyEnumType ; usando StringListMap = System . Colecciones . Genérico . Diccionario < cadena , System . Colecciones . Genérico . Lista < cadena >>;
En D, la palabra clave alias
[8] permite crear sinónimos de tipo o de tipo parcial.
struct Foo ( T ) {} alias FooInt = Foo ! int ; alias Fun = int delegate ( int );
Preocupaciones de uso
Kernighan y Ritchie indicaron dos razones para usar typedef. [1] Primero, proporciona un medio para hacer que un programa sea más portátil o más fácil de mantener. En lugar de tener que cambiar un tipo en cada aspecto a lo largo de los archivos fuente del programa, solo se necesita cambiar una única declaración typedef. size_t y ptrdiff_t en
Algunos programadores se oponen al uso extensivo de typedefs. La mayoría de los argumentos se centran en la idea de que typedefs simplemente oculta el tipo de datos real de una variable. Por ejemplo, Greg Kroah-Hartman , un pirata informático y documentalista del kernel de Linux , desaconseja su uso para cualquier cosa que no sean declaraciones de prototipos de funciones. Argumenta que esta práctica no solo confunde innecesariamente el código, sino que también puede hacer que los programadores hagan un mal uso accidental de grandes estructuras pensando que son tipos simples. [9]
Ver también
- Tipo de datos abstracto
- Sintaxis C
Referencias
- ↑ a b Kernighan, Brian W .; Ritchie, Dennis M. (1988). El lenguaje de programación C (2ª ed.). Englewood Cliffs, Nueva Jersey: Prentice Hall. pag. 147 . ISBN 0-13-110362-8. Consultado el 18 de junio de 2016 .
C proporciona una función llamada typedef para crear nuevos nombres de tipos de datos. … Debe enfatizarse que una declaración typedef no crea un nuevo tipo en ningún sentido; simplemente agrega un nuevo nombre para algún tipo existente.
- ^ "calificador de tipo const" . cppreference.com . Consultado el 20 de octubre de 2020 .
- ^ "especificador typedef" . cppreference.com . Consultado el 18 de junio de 2016 .
- ^ Deitel, Paul J .; Deitel, HM (2007). C cómo programar (5ª ed.). Upper Saddle River, Nueva Jersey: Pearson Prentice Hall. ISBN 9780132404167. Consultado el 12 de septiembre de 2012 .
Los nombres de los tipos de estructura a menudo se definen con typedef para crear nombres de tipos más cortos.
- ^ a b "Escriba alias, plantilla de alias (desde C ++ 11) - cppreference.com" . en.cppreference.com . Consultado el 25 de septiembre de 2018 .
- ^ Tala, Deepak Kumar. "Tipos de datos SystemVerilog Parte-V" . www.asic-world.com . ASIC World . Consultado el 25 de septiembre de 2018 .
- ^ http://msdn.microsoft.com/en-us/library/aa664765(VS.71).aspx
- ^ "Declaraciones - Lenguaje de programación D" . dlang.org . Consultado el 28 de mayo de 2017 .
- ^ Kroah-Hartman, Greg (1 de julio de 2002 ). "Estilo adecuado de codificación del kernel de Linux" . Diario de Linux . Consultado el 23 de septiembre de 2007 .
El uso de typedef solo oculta el tipo real de una variable.