Type
(См. также арифметические типы для подробностей о большинстве встроенных типов и список утилит, связанных с типами которые предоставляются библиотекой C.)
Объекты , функции и выражения обладают свойством, называемым тип , которое определяет интерпретацию двоичного значения, хранящегося в объекте или вычисляемого выражением.
Содержание |
Классификация типов
Система типов C++ состоит из следующих типов:
- тип void
- базовые типы
-
- тип char
- знаковые целочисленные типы
-
- стандартные: signed char , short , int , long , long long (начиная с C99)
|
(начиная с C23) |
|
(начиная с C99) |
-
- беззнаковые целочисленные типы
-
- стандартные: _Bool , (since C99) unsigned char , unsigned short , unsigned int , unsigned long , unsigned long long (since C99)
|
(начиная с C23) |
|
(начиная с C99) |
-
- типы с плавающей запятой
-
- вещественные типы с плавающей запятой: float , double , long double
|
(начиная с C23) |
|
(начиная с C99) |
- производные типы
| (since C11) |
Для каждого из перечисленных выше типов может существовать несколько квалифицированных версий его типа, соответствующих комбинациям одного, двух или всех трёх квалификаторов
const
,
volatile
и
restrict
(где это допускается семантикой квалификатора).
Группы типов
- типы объектов : все типы, которые не являются типами функций
- символьные типы : char , signed char , unsigned char
- целочисленные типы : char , знаковые целочисленные типы, беззнаковые целочисленные типы, перечисляемые типы
- вещественные типы : целочисленные типы и типы вещественных чисел с плавающей точкой
- арифметические типы : целочисленные типы и типы с плавающей точкой
- скалярные типы : арифметические типы, указательные типы , и nullptr_t (начиная с C23)
- агрегатные типы : массивы и структуры
- производные типы деклараторов : массивы, типы функций и указатели
Создание полного типа объекта, для которого количество байтов в представлении объекта не может быть представлено в типе
size_t
(т.е. в результирующем типе оператора
sizeof
)
, включая формирование такого типа VLA во время выполнения,
(начиная с C99)
является неопределенным поведением.
Совместимые типы
В программе на C объявления, ссылающиеся на один и тот же объект или функцию в разных единицах трансляции , не обязаны использовать один и тот же тип. Они должны использовать лишь достаточно похожие типы, формально известные как совместимые типы . То же самое относится к вызовам функций и доступу к lvalue; типы аргументов должны быть совместимы с типами параметров, а тип выражения lvalue должен быть совместим с типом объекта, к которому осуществляется доступ.
Типы
T
и
U
являются совместимыми, если
-
они являются одним и тем же типом (одинаковое имя или псевдонимы, введённые с помощью
typedef) - они являются идентично cvr-квалифицированными версиями совместимых неквалифицированных типов
- они являются указателями и указывают на совместимые типы
- они являются массивами, и
-
- их типы элементов совместимы, и
- если оба имеют постоянный размер, этот размер одинаков. Примечание: массивы неизвестной границы совместимы с любым массивом совместимого типа элемента. VLA совместим с любым массивом совместимого типа элемента. (since C99)
- они оба являются типами структур/объединений/перечислений, и
-
- (C99) если один объявлен с тегом, другой также должен быть объявлен с тем же тегом.
- если оба являются завершенными типами, их члены должны точно соответствовать по количеству, быть объявлены с совместимыми типами и иметь совпадающие имена.
- дополнительно, если они являются перечислениями, соответствующие члены также должны иметь одинаковые значения.
- дополнительно, если они являются структурами или объединениями,
-
- Соответствующие члены должны быть объявлены в том же порядке (только для структур)
- Соответствующие битовые поля должны иметь одинаковую ширину.
- один является перечислимым типом, а другой — базовым типом этого перечисления
- они являются типами функций, и
-
- их возвращаемые типы совместимы
- они обе используют списки параметров, количество параметров (включая использование многоточия) одинаково, и соответствующие параметры после применения преобразований типов массив-в-указатель и функция-в-указатель и после удаления квалификаторов верхнего уровня имеют совместимые типы
|
(до C23) |
Тип char не совместим с signed char и не совместим с unsigned char .
Если две декларации ссылаются на один и тот же объект или функцию и не используют совместимые типы, поведение программы не определено.
// Единица трансляции 1 struct S { int a; }; extern struct S *x; // совместим с x из ЕТ2, но не с x из ЕТ3 // Единица трансляции 2 struct S; extern struct S *x; // совместим с обоими x // Единица трансляции 3 struct S { float a; }; extern struct S *x; // совместим с x из ЕТ2, но не с x из ЕТ1 // поведение не определено
// Translation Unit 1 #include <stdio.h> struct s { int i; }; // совместимо с s из TU3, но не с s из TU2 extern struct s x = {0}; // совместимо с x из TU3 extern void f(void); // совместимо с f из TU2 int main() { f(); return x.i; } // Translation Unit 2 struct s { float f; }; // совместимо с s из TU4, но не с s из TU1 extern struct s y = {3.14}; // совместимо с y из TU4 void f() // совместимо с f из TU1 { return; } // Translation Unit 3 struct s { int i; }; // совместимо с s из TU1, но не с s из TU2 extern struct s x; // совместимо с x из TU1 // Translation Unit 4 struct s { float f; }; // совместимо с s из TU2, но не с s из TU1 extern struct s y; // совместимо с y из TU2 // поведение определено корректно: только множественные объявления // объектов и функций должны иметь совместимые типы, но не сами типы
Примечание: В C++ отсутствует концепция совместимых типов. Программа на языке C, которая объявляет два типа, совместимых, но не идентичных в разных единицах трансляции, не является корректной программой на C++.
Составные типы
Составной тип может быть сконструирован из двух совместимых типов; это тип, который совместим с обоими исходными типами и удовлетворяет следующим условиям:
- Если оба типа являются массивами, применяются следующие правила:
-
- Если один тип является массивом известного постоянного размера, то составной тип является массивом этого размера.
|
(начиная с C99) |
-
- В противном случае оба типа являются массивами неизвестного размера, и составной тип представляет собой массив неизвестного размера.
- Тип элемента составного типа является составным типом двух типов элементов.
|
(до C23) |
- Если оба типа являются типами функций со списками параметров, тип каждого параметра в составном списке параметров является составным типом соответствующих параметров.
Эти правила применяются рекурсивно к типам, от которых производятся два типа.
// Даны следующие две декларации в области видимости файла: int f(int (*)(), double (*)[3]); int f(int (*)(char *), double (*)[]); // C23: Ошибка: конфликтующие типы для 'f' // Результирующий составной тип для функции: int f(int (*)(char *), double (*)[3]);
Для идентификатора с внутренней или внешней линковкой , объявленного в области видимости, где видно предыдущее объявление этого идентификатора, если предыдущее объявление указывает внутреннюю или внешнюю линковку, тип идентификатора в последующем объявлении становится композитным типом.
Неполные типы
Неполный тип — это тип объекта, для которого недостаточно информации, чтобы определить размер объектов этого типа. Неполный тип может быть завершён в некоторой точке единицы трансляции.
Следующие типы являются неполными:
- тип void . Этот тип не может быть завершён.
- тип массива неизвестного размера. Может быть завершён последующим объявлением, указывающим размер.
extern char a[]; // тип a является неполным (обычно встречается в заголовочном файле) char a[10]; // тип a теперь является полным (обычно встречается в исходном файле)
- структура или объединение неизвестного содержания. Может быть завершена объявлением той же структуры или объединения, которое определяет её содержание позже в той же области видимости.
struct node { struct node* next; // структура node неполна в этой точке }; // структура node завершена в этой точке
Имена типов
Тип может потребоваться указать в контексте, отличном от объявления . В таких ситуациях используется имя типа , которое грамматически представляет собой в точности такой же список спецификаторов типа и квалификаторов типа , за которым следует декларатор (см. объявления ), как если бы мы объявляли единственный объект или функцию этого типа, за исключением того, что идентификатор опускается:
int n; // объявление целочисленной переменной sizeof(int); // использование имени типа int *a[3]; // объявление массива из 3 указателей на int sizeof(int *[3]); // использование имени типа int (*p)[3]; // объявление указателя на массив из 3 int sizeof(int (*)[3]); // использование имени типа int (*a)[*] // объявление указателя на VLA (в параметре функции) sizeof(int (*)[*]) // использование имени типа (в параметре функции) int *f(void); // объявление функции sizeof(int *(void)); // использование имени типа int (*p)(void); // объявление указателя на функцию sizeof(int (*)(void)); // использование имени типа int (*const a[])(unsigned int, ...) = {0}; // массив указателей на функции sizeof(int (*const [])(unsigned int, ...)); // использование имени типа
За исключением того, что избыточные скобки вокруг идентификатора значимы в имени типа и представляют "функцию без спецификации параметров":
int (n); // объявляет n типа int sizeof(int ()); // использует тип "функция, возвращающая int"
Имена типов используются в следующих ситуациях:
| (начиная с C99) | |
| (начиная с C11) |
Имя типа может вводить новый тип:
void* p = (void*)(struct X { int i; } *)0; // имя типа "struct X {int i;}*", используемое в выражении приведения типа // вводит новый тип "struct X" struct X x = {1}; // struct X теперь в области видимости
Ссылки
- Стандарт 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++ документация
для
Type
|