Spec-Zone.ru › C

Тип

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

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

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

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

  • тип void
  • базовые типы
  • тип char
  • целые типы со знаком
    • стандартные: signed char, short, int, long, long long(с C99)
  • битовые: _BitInt(N), где N — целочисленное константное выражение, указывающее количество битов, используемых для представления типа, включая бит знака. Каждое значение N определяет отдельный тип.
(с C23)
  • расширенные: определяется реализацией, например __int128
(с C99)
  • целые типы без знака
    • стандартные: _Bool,(с C99) unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long(с C99)
  • битовые: unsigned _BitInt(N), где N — целочисленное константное выражение, указывающее количество битов, используемых для представления типа. Каждое значение N определяет отдельный тип. Эта категория включает тип unsigned _BitInt(1), которому не соответствует битовый цельный тип со знаком
(с C23)
  • расширенные: определяется реализацией, например __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)
  • перечисляемые типы
  • производные типы
    • массивы
    • структуры
    • объединения
    • типы функций
    • указатели
  • атомарные типы
(с 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 совместим с любым массивом совместимого типа элемента.(с C99)
  • они являются структурами/объединениями/перечислениями, и
  • (C99)если один объявлен с тегом, другой также должен быть объявлен с тем же тегом.
  • если оба являются полными типами, их члены должны соответствовать по количеству, быть объявлены со совместимыми типами и иметь совпадающие имена.
  • дополнительно, если они являются перечислениями, соответствующие члены также должны иметь одинаковые значения.
  • дополнительно, если они являются структурами или объединениями,
    • Соответствующие члены должны быть объявлены в том же порядке (только для структур)
    • Соответствующие битовые поля должны иметь одинаковую ширину.
  • один является перечисляемым типом, а другой — базовым типом этого перечисления
  • они являются типами функций, и
    • их возвращаемые типы совместимы
    • они оба используют списки параметров, количество параметров (включая использование многоточия) одинаково, и соответствующий параметр после применения корректировок типа массива-указатель и функции-указатель и после удаления квалификаторов верхнего уровня имеет совместимые типы
  • один является старым стилем (без параметров), другой имеет список параметров, список параметров не использует многоточие и каждый параметр совместим (после корректировки типа параметра функции) с соответствующим параметром старого стиля после продвижения аргументов по умолчанию
  • одно объявление старого стиля (без параметров), другое имеет список параметров, список параметров не использует многоточие, и все параметры (после корректировки типа параметра функции) не подвергаются влиянию продвижения аргументов по умолчанию
(до C23)

Тип char не совместим с signed char и не совместим с unsigned char.

Если два объявления относятся к одному объекту или функции и не используют совместимые типы, поведение программы неопределено.

// 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++.

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

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

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

Имена типов используются в следующих ситуациях:

  • приведение типов
  • sizeof
  • литерал составного типа
(с C99)
  • обобщённый выбор
  • _Alignof
  • _Alignas
  • _Atomic (при использовании в качестве спецификатора типа)
(с 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:2023):
    • 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/w/c/language/type

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API