Type
(Véase también tipos aritméticos para los detalles sobre la mayoría de los tipos incorporados y la lista de utilidades relacionadas con tipos que proporciona la biblioteca de C.)
Objetos , funciones , y expresiones tienen una propiedad llamada tipo , que determina la interpretación del valor binario almacenado en un objeto o evaluado por la expresión.
Contenidos |
Clasificación de tipos
El sistema de tipos de C consta de los siguientes tipos:
- el tipo void
- tipos básicos
-
- el tipo char
- tipos enteros con signo
-
- estándar: signed char , short , int , long , long long (desde C99)
|
(desde C23) |
|
(desde C99) |
-
- tipos de enteros sin signo
-
- estándar: _Bool , (since C99) unsigned char , unsigned short , unsigned int , unsigned long , unsigned long long (since C99)
|
(desde C23) |
|
(desde C99) |
-
- tipos de punto flotante
-
- tipos de punto flotante reales: float , double , long double
|
(desde C23) |
|
(desde C99) |
- tipos derivados
| (desde C11) |
Para cada tipo listado anteriormente, pueden existir varias versiones calificadas de su tipo, correspondientes a las combinaciones de uno, dos o los tres de los
const
,
volatile
, y
restrict
calificadores (cuando esté permitido por la semántica del calificador).
Grupos de tipos
- tipos de objeto : todos los tipos que no son tipos de función
- tipos de carácter : char , signed char , unsigned char
- tipos enteros : char , tipos enteros con signo, tipos enteros sin signo, tipos enumerados
- tipos reales : tipos enteros y tipos de coma flotante real
- tipos aritméticos : tipos enteros y tipos de coma flotante
- tipos escalares : tipos aritméticos, tipos puntero , y nullptr_t (desde C23)
- tipos agregados : tipos array y tipos estructura
- tipos de declarador derivados : tipos array, tipos función y tipos puntero
Construir un tipo de objeto completo de manera que el número de bytes en su representación de objeto no sea representable en el tipo
size_t
(es decir, el tipo resultante del operador
sizeof
)
, incluyendo la formación de dicho tipo VLA en tiempo de ejecución,
(desde C99)
es comportamiento indefinido.
Tipos compatibles
En un programa C, las declaraciones que se refieren al mismo objeto o función en diferentes unidades de traducción no tienen que usar el mismo tipo. Solo tienen que usar tipos suficientemente similares, formalmente conocidos como tipos compatibles . Lo mismo se aplica a las llamadas a funciones y accesos a lvalues; los tipos de argumentos deben ser compatibles con los tipos de parámetros y el tipo de expresión lvalue debe ser compatible con el tipo de objeto al que se accede.
Los tipos
T
y
U
son compatibles, si
-
son del mismo tipo (mismo nombre o alias introducidos por un
typedef) - son versiones idénticamente calificadas cvr de tipos no calificados compatibles
- son tipos puntero y apuntan a tipos compatibles
- son tipos array, y
-
- sus tipos de elemento son compatibles, y
- si ambos tienen tamaño constante, ese tamaño es el mismo. Nota: los arrays de límite desconocido son compatibles con cualquier array de tipo de elemento compatible. VLA es compatible con cualquier array de tipo de elemento compatible. (desde C99)
- ambos son tipos de estructura/unión/enumeración, y
-
- (C99) si uno se declara con una etiqueta, el otro también debe declararse con la misma etiqueta.
- si ambos son tipos completos, sus miembros deben corresponder exactamente en número, declararse con tipos compatibles y tener nombres coincidentes.
- adicionalmente, si son enumeraciones, los miembros correspondientes también deben tener los mismos valores.
- adicionalmente, si son estructuras o uniones,
-
- Los miembros correspondientes deben declararse en el mismo orden (solo estructuras)
- Los campos de bits correspondientes deben tener los mismos anchos.
- uno es un tipo enumerado y el otro es el tipo subyacente de esa enumeración
- son tipos de función, y
-
- sus tipos de retorno son compatibles
- ambos utilizan listas de parámetros, el número de parámetros (incluyendo el uso de la elipsis) es el mismo, y el parámetro correspondiente, después de aplicar ajustes de tipo array-a-puntero y función-a-puntero y después de eliminar calificadores de nivel superior, tienen tipos compatibles
|
(hasta C23) |
El tipo char no es compatible con signed char y no es compatible con unsigned char .
Si dos declaraciones se refieren al mismo objeto o función y no utilizan tipos compatibles, el comportamiento del programa es indefinido.
// Unidad de Traducción 1 struct S { int a; }; extern struct S *x; // compatible con x de TU2, pero no con x de TU3 // Unidad de Traducción 2 struct S; extern struct S *x; // compatible con ambas x // Unidad de Traducción 3 struct S { float a; }; extern struct S *x; // compatible con x de TU2, pero no con x de TU1 // el comportamiento no está definido
// Unidad de Traducción 1 #include <stdio.h> struct s { int i; }; // compatible con s de TU3, pero no con s de TU2 extern struct s x = {0}; // compatible con x de TU3 extern void f(void); // compatible con f de TU2 int main() { f(); return x.i; } // Unidad de Traducción 2 struct s { float f; }; // compatible con s de TU4, pero no con s de TU1 extern struct s y = {3.14}; // compatible con y de TU4 void f() // compatible con f de TU1 { return; } // Unidad de Traducción 3 struct s { int i; }; // compatible con s de TU1, pero no con s de TU2 extern struct s x; // compatible con x de TU1 // Unidad de Traducción 4 struct s { float f; }; // compatible con s de TU2, pero no con s de TU1 extern struct s y; // compatible con y de TU2 // el comportamiento está bien definido: solo las declaraciones múltiples // de objetos y funciones deben tener tipos compatibles, no los tipos en sí mismos
Nota: C++ no tiene concepto de tipos compatibles. Un programa en C que declara dos tipos que son compatibles pero no idénticos en diferentes unidades de traducción no es un programa válido en C++.
Tipos compuestos
Un tipo compuesto puede construirse a partir de dos tipos que son compatibles; es un tipo que es compatible con ambos tipos y satisface las siguientes condiciones:
- Si ambos tipos son tipos de arreglo, se aplican las siguientes reglas:
-
- Si un tipo es un arreglo de tamaño constante conocido, el tipo compuesto es un arreglo de ese tamaño.
|
(desde C99) |
-
- De lo contrario, ambos tipos son arrays de tamaño desconocido y el tipo compuesto es un array de tamaño desconocido.
- El tipo de elemento del tipo compuesto es el tipo compuesto de los dos tipos de elemento.
|
(hasta C23) |
- Si ambos tipos son tipos de función con listas de tipos de parámetros, el tipo de cada parámetro en la lista de tipos de parámetros compuesta es el tipo compuesto de los parámetros correspondientes.
Estas reglas se aplican recursivamente a los tipos de los cuales se derivan los dos tipos.
// Dadas las siguientes dos declaraciones de ámbito de archivo: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // C23: Error: tipos conflictivos para 'f' // El tipo compuesto resultante para la función es: int f(int (*)(char *), double (*)[3]);
Para un identificador con enlace interno o externo declarado en un ámbito en el que una declaración previa de ese identificador es visible, si la declaración previa especifica enlace interno o externo, el tipo del identificador en la declaración posterior se convierte en el tipo compuesto.
Tipos incompletos
Un tipo incompleto es un tipo de objeto que carece de información suficiente para determinar el tamaño de los objetos de ese tipo. Un tipo incompleto puede completarse en algún punto de la unidad de traducción.
Los siguientes tipos están incompletos:
- el tipo void . Este tipo no puede ser completado.
- tipo array de tamaño desconocido. Puede ser completado mediante una declaración posterior que especifique el tamaño.
extern char a[]; // el tipo de a es incompleto (esto suele aparecer en un encabezado) char a[10]; // el tipo de a ahora está completo (esto suele aparecer en un archivo fuente)
- tipo de estructura o unión de contenido desconconocido. Puede ser completado mediante una declaración de la misma estructura o unión que defina su contenido posteriormente en el mismo ámbito.
struct node { struct node* next; // struct node está incompleto en este punto }; // struct node está completo en este punto
Nombres de tipos
Un tipo puede tener que ser nombrado en un contexto diferente al de la declaración . En estas situaciones, se utiliza el nombre de tipo , que es, gramaticalmente, exactamente igual que una lista de especificadores de tipo y calificadores de tipo , seguida por el declarador (ver declaraciones ) como se usaría para declarar un único objeto o función de este tipo, excepto que se omite el identificador:
int n; // declaración de un int sizeof(int); // uso de nombre de tipo int *a[3]; // declaración de un array de 3 punteros a int sizeof(int *[3]); // uso de nombre de tipo int (*p)[3]; // declaración de un puntero a array de 3 int sizeof(int (*)[3]); // uso de nombre de tipo int (*a)[*] // declaración de puntero a VLA (en un parámetro de función) sizeof(int (*)[*]) // uso de nombre de tipo (en un parámetro de función) int *f(void); // declaración de función sizeof(int *(void)); // uso de nombre de tipo int (*p)(void); // declaración de puntero a función sizeof(int (*)(void)); // uso de nombre de tipo int (*const a[])(unsigned int, ...) = {0}; // array de punteros a funciones sizeof(int (*const [])(unsigned int, ...)); // uso de nombre de tipo
Excepto que los paréntesis redundantes alrededor del identificador son significativos en un nombre de tipo y representan "función sin especificación de parámetros":
int (n); // declara n de tipo int sizeof(int ()); // utiliza el tipo "función que retorna int"
Los nombres de tipos se utilizan en las siguientes situaciones:
| (desde C99) | |
| (desde C11) |
Un nombre de tipo puede introducir un nuevo tipo:
void* p = (void*)(struct X { int i; } *)0; // el nombre de tipo "struct X {int i;}*" usado en la expresión de conversión // introduce el nuevo tipo "struct X" struct X x = {1}; // struct X ahora está en el ámbito
Referencias
- Estándar C23 (ISO/IEC 9899:2024):
-
- 6.2.5 Tipos (p: TBD)
-
- 6.2.6 Representaciones de tipos (p: TBD)
-
- 6.2.7 Tipo compatible y tipo compuesto (p: TBD)
- Estándar C17 (ISO/IEC 9899:2018):
-
- 6.2.5 Tipos (p: 31-33)
-
- 6.2.6 Representaciones de tipos (p: 31-35)
-
- 6.2.7 Tipo compatible y tipo compuesto (p: 35-36)
- Estándar C11 (ISO/IEC 9899:2011):
-
- 6.2.5 Tipos (p: 39-43)
-
- 6.2.6 Representaciones de tipos (p: 44-46)
-
- 6.2.7 Tipo compatible y tipo compuesto (p: 47-48)
- Estándar C99 (ISO/IEC 9899:1999):
-
- 6.2.5 Tipos (p: 33-37)
-
- 6.2.6 Representaciones de tipos (p: 37-40)
-
- 6.2.7 Tipo compatible y tipo compuesto (p: 40-41)
- Estándar C89/C90 (ISO/IEC 9899:1990):
-
- 3.1.2.5 Tipos
-
- 3.1.2.6 Tipo compatible y tipo compuesto
Véase también
|
Documentación de C++
para
Type
|