Тип
(См. также арифметические типы, где подробно описано большинство встроенных типов, и список утилит для работы с типами, предоставляемых библиотекой C.)
Объекты, функции и выражения обладают свойством, называемым типом, который определяет интерпретацию двоичного значения, хранящегося в объекте или вычисляемого выражением.
Классификация типов
Система типов C состоит из следующих типов:
- тип void
- базовые типы
- тип char
- знаковые целочисленные типы
- стандартные: signedchar, short, int, long, longlong(начиная с C99)
| (начиная с C23) |
| (начиная с C99) |
- беззнаковые целочисленные типы
- стандартные: _Bool,(начиная с C99) unsignedchar, unsignedshort, unsignedint, unsignedlong, unsignedlonglong(начиная с C99)
| (начиная с C23) |
| (начиная с C99) |
- типы с плавающей точкой
- вещественные типы с плавающей точкой: float, double, longdouble
| (начиная с C23) |
| (начиная с C99) |
- перечислимые типы
- производные типы
| (начиная с C11) |
Для каждого перечисленного выше типа могут существовать несколько квалифицированных версий, соответствующих комбинациям одного, двух или всех трёх квалификаторов const, volatile и restrict (если это допускается семантикой квалификаторов).
Группы типов
- типы объектов: все типы, кроме типов функций
- символьные типы: char, signedchar, unsignedchar
- целочисленные типы: char, знаковые целочисленные типы, беззнаковые целочисленные типы, перечислимые типы
- вещественные типы: целочисленные типы и вещественные типы с плавающей точкой
- арифметические типы: целочисленные типы и типы с плавающей точкой
-
скалярные типы: арифметические типы, типы указателей и
nullptr_t(начиная с C23) - агрегатные типы: типы массивов и типы структур
- типы, образованные производными деклараторами: типы массивов, типы функций и типы указателей
Создание полного типа объекта, размер представления которого в объекте в байтах не может быть представлен типом size_t (то есть типом результата оператора sizeof), в том числе создание такого типа VLA во время выполнения,(начиная с C99) приводит к неопределённому поведению.
Совместимые типы
В программе на C объявления, ссылающиеся на один и тот же объект или функцию в разных единицах трансляции, не обязаны использовать один и тот же тип. Достаточно, чтобы они использовали достаточно похожие типы, формально называемые совместимыми типами. То же относится к вызовам функций и доступу через lvalue: типы аргументов должны быть совместимы с типами параметров, а тип выражения lvalue должен быть совместим с типом объекта, к которому осуществляется доступ.
Типы T и U совместимы, если
- это один и тот же тип (одно и то же имя или псевдонимы, введённые с помощью
typedef) - это версии одного и того же неквалифицированного совместимого типа с идентичными квалификаторами cvr
- это типы указателей, указывающие на совместимые типы
- это типы массивов, и
- типы их элементов совместимы, и
- если оба массива имеют постоянный размер, то этот размер одинаков. Примечание: массивы с неизвестной границей совместимы с любым массивом с совместимым типом элемента. VLA совместим с любым массивом с совместимым типом элемента.(начиная с C99)
- это оба типа структур, объединений или перечислений, и
- (C99)если один объявлен с тегом, другой также должен быть объявлен с тем же тегом.
- если оба являются завершёнными типами, их члены должны в точности соответствовать друг другу по количеству, быть объявлены с совместимыми типами и иметь совпадающие имена.
- кроме того, если это перечисления, соответствующие элементы должны также иметь одинаковые значения.
- кроме того, если это структуры или объединения,
- соответствующие члены должны быть объявлены в одном порядке (только для структур)
- соответствующие битовые поля должны иметь одинаковую ширину.
- один тип является перечислимым, а другой — базовым типом этого перечисления
- это типы функций, и
- их типы возвращаемых значений совместимы
- оба используют списки параметров, количество параметров (включая наличие многоточия) одинаково, а соответствующие параметры после применения преобразований типов «массив в указатель» и «функция в указатель» и удаления квалификаторов верхнего уровня имеют совместимые типы
| (до C23) |
Тип char несовместим с типом signedchar и несовместим с типом unsignedchar.
Если два объявления ссылаются на один и тот же объект или функцию и используют несовместимые типы, поведение программы не определено.
// 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 with TU2's y
// the behavior is well-defined: only multiple declarations
// of objects and functions must have compatible types, not the types themselves
Примечание: в C++ нет понятия совместимых типов. Программа на C++, в которой в разных единицах трансляции объявлены два совместимых, но не идентичных типа, не является корректной программой на C++.
Составные типы
Составной тип можно построить из двух совместимых типов; это тип, совместимый с обоими исходными типами и удовлетворяющий следующим условиям:
- Если оба типа являются типами массивов, применяются следующие правила:
- Если один тип является массивом с известным постоянным размером, составной тип является массивом этого размера.
| (начиная с C99) |
- В противном случае оба типа являются массивами неизвестного размера, а составной тип — массивом неизвестного размера.
| (до C23) |
- Если оба типа являются типами функций со списками типов параметров, тип каждого параметра в составном списке типов параметров является составным типом соответствующих параметров.
Эти правила рекурсивно применяются к типам, из которых получены два исходных типа.
// Given the following two file scope declarations: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // C23: Error: conflicting types for 'f' // The resulting composite type for the function is: int f(int (*)(char *), double (*)[3]);
Для идентификатора с внутренним или внешним связыванием, объявленного в области видимости, где доступно предыдущее объявление этого идентификатора, если предыдущее объявление указывает на внутреннее или внешнее связывание, тип идентификатора в последующем объявлении становится составным типом.
Незавершённые типы
Незавершённый тип — это тип объекта, для которого недостаточно информации, чтобы определить размер объектов этого типа. Незавершённый тип может быть завершён в некоторый момент единицы трансляции.
Следующие типы являются незавершёнными:
- тип void. Этот тип нельзя завершить.
- тип массива неизвестного размера. Его можно завершить последующим объявлением, задающим размер.
extern char a[]; // the type of a is incomplete (this typically appears in a header) char a[10]; // the type of a is now complete (this typically appears in a source file)
- тип структуры или объединения с неизвестным содержимым. Его можно завершить объявлением той же структуры или того же объединения, которое определяет его содержимое позднее в той же области видимости.
struct node
{
struct node* next; // struct node is incomplete at this point
}; // struct node is complete at this point
Имена типов
В некоторых контекстах тип может потребоваться указать не в объявлении. В таких случаях используется имя типа, которое грамматически в точности совпадает со списком спецификаторов типа и квалификаторов типа, за которым следует декларатор (см. объявления), как если бы объявлялся отдельный объект или функция этого типа, но без идентификатора:
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
Однако избыточные скобки вокруг идентификатора имеют значение в имени типа и обозначают «функцию без спецификации параметров»:
int (n); // declares n of type int sizeof(int ()); // uses type "function returning int"
Имена типов используются в следующих случаях:
| (начиная с C99) | |
| (начиная с C11) |
Имя типа может вводить новый тип:
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
Ссылки
- Стандарт C23 (ISO/IEC 9899:2024):
- 6.2.5 Типы (с.: TBD)
- 6.2.6 Представления типов (с.: TBD)
- 6.2.7 Совместимый тип и составной тип (с.: TBD)
- Стандарт C17 (ISO/IEC 9899:2018):
- 6.2.5 Типы (с.: 31-33)
- 6.2.6 Представления типов (с.: 31-35)
- 6.2.7 Совместимый тип и составной тип (с.: 35-36)
- Стандарт C11 (ISO/IEC 9899:2011):
- 6.2.5 Типы (с.: 39-43)
- 6.2.6 Представления типов (с.: 44-46)
- 6.2.7 Совместимый тип и составной тип (с.: 47-48)
- Стандарт C99 (ISO/IEC 9899:1999):
- 6.2.5 Типы (с.: 33-37)
- 6.2.6 Представления типов (с.: 37-40)
- 6.2.7 Совместимый тип и составной тип (с.: 40-41)
- Стандарт C89/C90 (ISO/IEC 9899:1990):
- 3.1.2.5 Типы
- 3.1.2.6 Совместимый тип и составной тип
См. также
| Документация по C++ о типе |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/c/language/compatible_type