Namespaces
Variants

Type

From cppreference.net

(См. также арифметические типы для подробностей о большинстве встроенных типов и список утилит, связанных с типами которые предоставляются библиотекой C.)

Объекты , функции и выражения обладают свойством, называемым тип , которое определяет интерпретацию двоичного значения, хранящегося в объекте или вычисляемого выражением.

Содержание

Классификация типов

Система типов C++ состоит из следующих типов:

  • тип void
  • базовые типы
  • тип char
  • знаковые целочисленные типы
  • стандартные: signed char , short , int , long , long long (начиная с C99)
  • битово-точный: _BitInt ( N ) где N - целочисленное константное выражение, определяющее количество битов, используемых для представления типа, включая знаковый бит. Каждое значение N обозначает отдельный тип.
(начиная с C23)
  • расширенный: определяется реализацией, например __int128
(начиная с C99)
  • беззнаковые целочисленные типы
  • стандартные: _Bool , (since C99) unsigned char , unsigned short , unsigned int , unsigned long , unsigned long long (since C99)
  • bit-precise: unsigned _BitInt ( N ) где N является целочисленным константным выражением, которое определяет количество битов, используемых для представления типа. Каждое значение N обозначает отдельный тип. Эта категория включает тип unsigned _BitInt ( 1 ) который не имеет соответствующего битово-точного знакового целочисленного типа.
(начиная с C23)
  • extended: определяется реализацией, например __uint128
(начиная с C99)
  • типы с плавающей запятой
  • вещественные типы с плавающей запятой: float , double , long double
  • десятичные вещественные типы с плавающей запятой: _Decimal32 , _Decimal64 , _Decimal128
(начиная с C23)
  • комплексные типы: float _Complex , double _Complex , long double _Complex
  • мнимые типы: float _Imaginary , double _Imaginary , long double _Imaginary
(начиная с 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++.

Составные типы

Составной тип может быть сконструирован из двух совместимых типов; это тип, который совместим с обоими исходными типами и удовлетворяет следующим условиям:

  • Если оба типа являются массивами, применяются следующие правила:
  • Если один тип является массивом известного постоянного размера, то составной тип является массивом этого размера.
  • В противном случае, если один тип является VLA, размер которого задан выражением, которое не вычисляется, программа, требующая составного типа обоих типов, имеет неопределённое поведение.
  • В противном случае, если один тип является VLA с указанным размером, составной тип является VLA этого размера.
  • В противном случае, если один тип является VLA с неуказанным размером, составной тип является VLA с неуказанным размером.
(начиная с 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 Совместимый тип и составной тип

Смотрите также