Spec-Zone.ru › C

Тип

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

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

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

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

  • тип void
  • базовые типы
  • тип char
  • знаковые целочисленные типы
    • стандартные: signedchar, short, int, long, longlong(начиная с C99)
  • с точной разрядностью: _BitInt(N), где N — целочисленное константное выражение, задающее количество битов, используемых для представления типа, включая знаковый бит. Каждое значение N обозначает отдельный тип.
(начиная с C23)
  • расширенные: определяются реализацией, например __int128
(начиная с C99)
  • беззнаковые целочисленные типы
    • стандартные: _Bool,(начиная с C99) unsignedchar, unsignedshort, unsignedint, unsignedlong, unsignedlonglong(начиная с C99)
  • с точной разрядностью: unsigned_BitInt(N), где N — целочисленное константное выражение, задающее количество битов, используемых для представления типа. Каждое значение N обозначает отдельный тип. Эта категория включает тип unsigned_BitInt(1), которому не соответствует знаковый целочисленный тип с точной разрядностью.
(начиная с C23)
  • расширенные: определяются реализацией, например __uint128
(начиная с C99)
  • типы с плавающей точкой
    • вещественные типы с плавающей точкой: float, double, longdouble
  • десятичные вещественные типы с плавающей точкой: _Decimal32, _Decimal64, _Decimal128
(начиная с C23)
  • комплексные типы: float_Complex, double_Complex, longdouble_Complex
  • мнимые типы: float_Imaginary, double_Imaginary, longdouble_Imaginary
(начиная с 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++.

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

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

  • Если оба типа являются типами массивов, применяются следующие правила:
    • Если один тип является массивом с известным постоянным размером, составной тип является массивом этого размера.
  • В противном случае, если один тип является 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(до C23)alignof(начиная с C23)
  • _Alignas(до C23)alignas(начиная с C23)
  • _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: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

Spec-Zone.ru

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