(See also arithmetic types for the details on most built-in types and the list of type-related utilities that are provided by the C library).
Objects, functions, and expressions have a property called type, which determines the interpretation of the binary value stored in an object or evaluated by the expression.
The C type system consists of the following types:
void
char
signed char
, short
, int
, long
, long long
(since C99) __int128
_Bool
(since C99), unsigned char
, unsigned short
, unsigned int
, unsigned long
, unsigned long long
(since C99) __uint128
float
, double
, long double
float _Complex
, double _Complex
, long double _Complex
float _Imaginary
, double _Imaginary
, long double _Imaginary
For every type listed above several qualified versions of its type may exist, corresponding to the combinations of one, two, or all three of the const, volatile, and restrict qualifiers (where allowed by the qualifier's semantics).
char
, signed char
, unsigned char
char
, signed integer types, unsigned integer types, enumerated types In a C program, the declarations referring to the same object or function in different translation units do not have to use the same type. They only have to use sufficiently similar types, formally known as compatible types. Same applies to function calls and lvalue accesses; argument types must be compatible with parameter types and lvalue expression type must be compatible with the object type that is accessed.
The types T
and U
are compatible, if.
The type char
is not compatible with signed char
and not compatible with unsigned char
.
If two declarations refer to the same object or function and do not use compatible types, the behavior of the program is undefined.
// Translation Unit 1 struct S {int a;}; extern struct S *x; // compatible with TU2's x, but not with TU3's x // Translation Unit 2 struct S; extern struct S *x; // compatible with both x's // Translation Unit 3 struct S {float a;}; extern struct S *x; // compatible with TU2's x, but not with TU1's x // the behavior is undefined
// Translation Unit 1 #include <stdio.h> struct s {int i;}; // compatible with TU3's s, but not TU2's extern struct s x = {0}; // compatible with TU3's x extern void f(void); // compatible with TU2's f int main() { f(); return x.i; } // Translation Unit 2 struct s {float f;}; // compatible with TU4's s, but not TU1's s extern struct s y = {3.14}; // compatible with TU4's y void f() // compatible with TU1's f { return; } // Translation Unit 3 struct s {int i;}; // compatible with TU1's s, but not TU2's s extern struct s x; // compatible with TU1's x // Translation Unit 4 struct s {float f;}; // compatible with TU2's s, but not TU1's s extern struct s y; // compatible iwth TU2's y // the behavior is well-defined: only multiple declarations // of objects and functions must have compatible types, not the types themselves
Note: C++ has no concept of compatible types. A C program that declares two types that are compatible but not identical in different translation units is not a valid C++ program.
An incomplete type is an object type that lacks sufficient information to determine the size of the objects of that type. An incomplete type may be completed at some point in the translation unit.
The following types are incomplete:
void
. This type cannot be completed. A type may have to be named in context other than the declaration. In these situations, type name is used, which is, grammatically, exactly the same as a list of type-specifiers and type-qualifiers, followed by the declarator (see declarations) as would be used to declare a single object or function of this type, except that the identifier is omitted:
int n; // declaration of an int sizeof(int); // use of type name int *a[3]; // declaration of an array of 3 pointers to int sizeof(int *[3]); // use of type name int (*p)[3]; // declaration of a pointer to array of 3 int sizeof(int (*)[3]); // use of type name int (*a)[*] // declaration of pointer to VLA (in a function parameter) sizeof(int (*)[*]) // use of type name (in a function parameter) int *f(void); // declaration of function sizeof(int *(void)); // use of type name int (*p)(void); // declaration of pointer to function sizeof(int (*)(void)); // use of type name int (*const a[])(unsigned int, ...) = {0}; // array of pointers to functions sizeof(int (*const [])(unsigned int, ...)); // use of type name
Except the redundant parentheses around the identifier are meaningful in a type-name and represent "function with no parameter specification":
int (n); // declares n of type int sizeof(int ()); // uses type "function returning int"
Type names are used in the following situations:
(since C99) | |
| (since C11) |
A type name may introduce a new type:
void* p = (void*)(struct X {int i;} *)0; // type name "struct X {int i;}*" used in the cast expression // introduces the new type "struct X" struct X x = {1}; // struct X is now in scope
C++ documentation for Type |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/c/language/types