stringtranslate.com

Типы данных C

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

Язык C предоставляет основные арифметические типы, такие как целые и действительные типы чисел, а также синтаксис для построения массивов и составных типов. Заголовки для стандартной библиотеки C , которые должны использоваться через директивы include , содержат определения типов поддержки, которые имеют дополнительные свойства, такие как предоставление хранилища с точным размером, независимо от реализации языка на конкретных аппаратных платформах. [1] [2]

Основные типы

Основные типы

Язык C предоставляет четыре основных спецификатора арифметических типов char , int , float и double , а также модификаторы signed , unsigned , short и long . В следующей таблице перечислены допустимые комбинации при указании большого набора объявлений, специфичных для размера хранилища.

  1. ^ abcde Минимальные диапазоны [−(2 n −1 −1), 2 n −1 −1] (например, [−127,127]) берутся из различных целочисленных представлений, разрешенных стандартом ( дополнение до единицы , знаковая величина , дополнение до двух ). [4] Однако большинство платформ используют дополнение до двух, подразумевая диапазон вида [−2 m −1 , 2 m −1 −1] с mn для этих реализаций, например, [−128,127] ( SCHAR_MIN == −128и SCHAR_MAX == 127) для 8-битного знакового символа . Начиная с C23, единственным разрешенным представлением является дополнение до двух, поэтому значения варьируются по крайней мере от [−2 n −1 , 2 n −1 −1] . [5]
  2. ^ или %hhiдля числового вывода
  3. ^ или %hhuдля числового вывода
  4. ^ Эти строки форматирования также существуют для форматирования текста, но работают с двойной точностью.
  5. ^ ab Верхний регистр отличается от нижнего в выводе. Спецификаторы верхнего регистра создают значения в верхнем регистре, а нижнего — в нижнем (%A, %E, %F, %G создают такие значения, как INF, NAN и E (экспонента) в верхнем регистре)

Фактический размер целочисленных типов зависит от реализации. Стандарт требует только соотношения размеров между типами данных и минимальные размеры для каждого типа данных:

Требования к отношению таковы, что long longне меньше long , который не меньше int , который не меньше short . Поскольку размер char всегда является минимальным поддерживаемым типом данных, никакие другие типы данных (кроме битовых полей ) не могут быть меньше.

Минимальный размер для char составляет 8 бит, минимальный размер для short и int составляет 16 бит, для long он составляет 32 бита и должен содержать не менее 64 бит.long long

Тип int должен быть целочисленным типом, с которым целевой процессор работает наиболее эффективно. Это обеспечивает большую гибкость: например, все типы могут быть 64-битными. Однако популярны несколько различных схем целочисленной ширины (моделей данных). Поскольку модель данных определяет, как взаимодействуют разные программы, в данном интерфейсе приложения операционной системы используется единая модель данных. [9]

На практике char обычно имеет размер 8 бит, а short — 16 бит (как и их беззнаковые аналоги). Это справедливо для таких разных платформ, как SunOS  4 Unix 1990-х годов, Microsoft MS-DOS , современный Linux и Microchip MCC18 для встроенных 8-битных микроконтроллеров PIC . POSIX требует , чтобы char имел размер ровно 8 бит. [10] [11]

Различные правила стандарта C делают unsigned charбазовый тип, используемый для массивов, подходящим для хранения произвольных объектов, не являющихся битовыми полями: отсутствие битов заполнения и представлений ловушек, определение представления объекта [7] и возможность псевдонимов. [12]

Фактический размер и поведение типов с плавающей точкой также различаются в зависимости от реализации. Единственное требование — long doubleне быть меньше double , который не меньше float . Обычно для float и double используются 32-битный и 64-битный двоичные форматы с плавающей точкой IEEE 754 соответственно.

Стандарт C99 включает новые действительные типы с плавающей точкой float_t и double_t , определенные в . Они соответствуют типам, используемым для промежуточных результатов выражений с плавающей точкой, когда FLT_EVAL_METHOD равен 0, 1 или 2. Эти типы могут быть шире, чем .<math.h>long double

C99 также добавил комплексные типы: float _Complex, double _Complex, long double _Complex. C11 добавил мнимые типы (которые были описаны в информативном приложении C99): float _Imaginary, double _Imaginary, long double _Imaginary. Включение заголовка <complex.h>позволяет получить доступ ко всем этим типам с использованием комплексного и мнимого соответственно.

Булев тип

C99 добавил тип данных Boolean _Bool . Кроме того, <stdbool.h>заголовок определяет boolкак удобный псевдоним для этого типа, а также предоставляет макросы для trueи false. _Boolфункции, аналогичные обычному целочисленному типу, с одним исключением: любые назначения a, _Boolкоторые не равны 0 (ложь), сохраняются как 1 (истина). Такое поведение существует для того, чтобы избежать целочисленных переполнений в неявных сужающихся преобразованиях. Например, в следующем коде:

беззнаковый символ b = 256 ;    если ( б ) { /* сделать что-то */ }  

Переменная bоценивается как false, если unsigned charимеет размер 8 бит. Это происходит потому, что значение 256 не помещается в тип данных, что приводит к использованию нижних 8 бит, что приводит к нулевому значению. Однако изменение типа приводит к тому, что предыдущий код ведет себя нормально:

_Bool b = 256 ;   если ( б ) { /* сделать что-то */ }  

Тип _Bool также гарантирует, что истинные значения всегда будут равны друг другу:

_Bool a = 1 , b = 2 ;      если ( a == b ) { /* этот код будет запущен */ }    

Целочисленные типы с точностью до бита

Начиная с C23 , язык позволяет программисту определять целые числа, имеющие ширину произвольного числа бит. Эти типы указываются как , где N — целочисленное константное выражение, которое обозначает число бит, включая бит знака для знаковых типов, представленных в дополнительном коде. Максимальное значение N предоставляется и составляет не менее . Таким образом, тип (или ) принимает значения от −2 до 1, а принимает значения от 0 до 3. Тип также существует, будучи либо 0, либо 1, и не имеет эквивалентного знакового типа. [13]_BitInt(N)BITINT_MAXWIDTHULLONG_WIDTH_BitInt(2)signed _BitInt(2)unsigned _BitInt(2)unsigned _BitInt(1)

Типы различий размеров и указателей

Спецификация языка C включает typedef s и для представления связанных с памятью величин. Их размер определяется в соответствии с арифметическими возможностями целевого процессора, а не возможностями памяти, такими как доступное адресное пространство. Оба эти типа определены в заголовке ( в C++).size_tptrdiff_t<stddef.h>cstddef

size_t— это тип целого числа без знака, используемый для представления размера любого объекта (включая массивы) в конкретной реализации. Оператор sizeof возвращает значение типа . Максимальный размер предоставляется через , макроконстанту, которая определена в заголовке ( заголовок в C++). гарантированно имеет ширину не менее 16 бит. Кроме того, POSIX включает , который является типом целого числа со знаком той же ширины, что и .size_tsize_tSIZE_MAX<stdint.h>cstdintsize_tssize_tsize_t

ptrdiff_t— это знаковый целочисленный тип, используемый для представления разницы между указателями. Он гарантированно действителен только для указателей одного типа; вычитание указателей, состоящих из разных типов, определяется реализацией.

Интерфейс к свойствам базовых типов

Информация о фактических свойствах, таких как размер, основных арифметических типов, предоставляется через макроконстанты в двух заголовках: <limits.h>заголовок ( climitsheader в C++) определяет макросы для целочисленных типов, а <float.h>заголовок ( cfloatheader в C++) определяет макросы для типов с плавающей точкой. Фактические значения зависят от реализации.

Свойства целочисленных типов

Свойства типов с плавающей точкой

Целочисленные типы фиксированной ширины

Стандарт C99 включает определения нескольких новых целочисленных типов для улучшения переносимости программ. [2] Уже имеющиеся базовые целочисленные типы были признаны недостаточными, поскольку их фактические размеры определяются реализацией и могут различаться в разных системах. Новые типы особенно полезны во встроенных средах , где оборудование обычно поддерживает только несколько типов, и эта поддержка различается в разных средах. Все новые типы определены в <inttypes.h>заголовке ( cinttypesheader в C++) и также доступны в <stdint.h>заголовке ( cstdintheader в C++). Типы можно сгруппировать в следующие категории:

В следующей таблице приведены типы и интерфейс для получения подробностей реализации ( n относится к количеству бит):

Спецификаторы формата Printf и scanf

Заголовок <inttypes.h>( cinttypesв C++) предоставляет возможности, которые расширяют функциональность типов, определенных в <stdint.h>заголовке. Он определяет макросы для спецификаторов формата printf и scanf, соответствующие типам, определенным в <stdint.h>, и несколько функций для работы с типами intmax_tи uintmax_t. Этот заголовок был добавлен в C99 .

Строка формата Printf

Макросы имеют формат . Здесь {fmt} определяет форматирование вывода и может быть одним из следующих: (десятичное), (шестнадцатеричное), (восьмеричное), (беззнаковое) и (целое). {type} определяет тип аргумента и может быть одним из следующих : , , , , , где соответствует количеству бит в аргументе.PRI{fmt}{type}dxouinFASTnLEASTnPTRMAXn

Строка формата Scanf

Макросы имеют формат . Здесь {fmt} определяет форматирование вывода и может быть одним из следующих: (десятичное), (шестнадцатеричное), (восьмеричное), (беззнаковое) и (целое). {type} определяет тип аргумента и может быть одним из следующих : , , , , , где соответствует количеству бит в аргументе.SCN{fmt}{type}dxouinFASTnLEASTnPTRMAXn

Функции

Дополнительные типы с плавающей точкой

Аналогично целочисленным типам фиксированной ширины, стандарт ISO/IEC TS 18661 определяет типы с плавающей точкой для обмена IEEE 754 и расширенных форматов в двоичном и десятичном виде:

Структуры

Структуры объединяют хранение нескольких элементов данных, потенциально различающихся типов данных, в один блок памяти, на который ссылается одна переменная. В следующем примере объявляется тип данных struct birthday, содержащий имя и день рождения человека. За определением структуры следует объявление переменной John, которая выделяет необходимое хранилище.

struct birthday { char name [ 20 ]; int day ; int month ; int year ; };      структура день рождения Джона ;  

Размещение памяти структуры — это проблема языковой реализации для каждой платформы с некоторыми ограничениями. Адрес памяти первого члена должен совпадать с адресом самой структуры. Структуры могут быть инициализированы или назначены с использованием составных литералов. Функция может напрямую возвращать структуру, хотя это часто неэффективно во время выполнения. Начиная с C99 , структура также может заканчиваться гибким членом массива .

Структура, содержащая указатель на структуру своего типа, обычно используется для построения связанных структур данных :

структурный узел { int val ; структурный узел * следующий ; };     

Массивы

Для каждого типа T, за исключением типов void и function, существуют типы "массив Nэлементов типа T" . Массив — это коллекция значений, все одного типа, хранящихся в памяти последовательно. Массив размером Nиндексируется целыми числами от 0до включительно N−1. Вот краткий пример:

int cat [ 10 ]; // массив из 10 элементов, каждый типа int  

Массивы могут быть инициализированы составным инициализатором, но не назначены. Массивы передаются функциям путем передачи указателя на первый элемент. Многомерные массивы определяются как "массив массивов …" , и все, кроме самого внешнего измерения, должны иметь постоянный размер времени компиляции:

int a [ 10 ][ 8 ]; // массив из 10 элементов, каждый типа 'массив из 8 элементов int'  

Указатели

Каждый тип данных Tимеет соответствующий указатель типа наT . Указатель — это тип данных, содержащий адрес места хранения переменной определенного типа. Они объявляются с помощью *декларатора типа звездочка ( ), следующего за базовым типом хранения и предшествующего имени переменной. Пробелы до или после звездочки необязательны.

char * квадрат ; long * круг ; int * овал ;   

Указатели также могут быть объявлены для типов данных указателя, тем самым создавая несколько косвенных указателей, таких как char ** и int *** , включая указатели на типы массивов. Последние встречаются реже, чем массив указателей, и их синтаксис может быть запутанным:

char * pc [ 10 ]; // массив из 10 элементов 'указателя на char' char ( * pa )[ 10 ]; // указатель на массив из 10 элементов char    

Элементу pcтребуется десять блоков памяти размером с указательchar (обычно 40 или 80 байт на обычных платформах), но элемент paпредставляет собой только один указатель (размером 4 или 8 байт), а данные, на которые он ссылается, представляют собой массив из десяти байт ( ).sizeof *pa == 10

Профсоюзы

Тип объединения — это специальная конструкция, которая позволяет получить доступ к одному и тому же блоку памяти, используя выбор различных описаний типов. Например, объединение типов данных может быть объявлено для разрешения чтения одних и тех же данных как целого числа, числа с плавающей точкой или любого другого объявленного пользователем типа:

union { int i ; float f ; struct { unsigned int u ; double d ; } s ; } u ;         

Общий размер uравен размеру u.s– который является суммой размеров u.s.uи u.s.d– поскольку sбольше, чем iи f. При назначении чего-либо u.i, некоторые части u.fмогут быть сохранены, если u.iменьше, чем u.f.

Чтение из члена объединения — это не то же самое, что приведение, поскольку значение члена не преобразуется, а просто считывается.

Указатели на функции

Указатели функций позволяют ссылаться на функции с определенной сигнатурой. Например, для сохранения адреса стандартной функции absв переменной my_int_f:

int ( * my_int_f )( int ) = & abs ; // оператор & можно опустить, но он дает понять, что здесь используется «адрес» abs   

Указатели функций вызываются по имени, как и обычные вызовы функций. Указатели функций отделены от указателей и указателей void .

Типовые квалификаторы

Вышеупомянутые типы могут быть дополнительно охарактеризованы квалификаторами типов , что даст квалифицированный тип . По состоянию на 2014 год и C11 в стандарте C есть четыре квалификатора типов: const( C89 ), volatile( C89 ), restrict( C99 ) и _Atomic( C11 ) — последний имеет личное имя, чтобы избежать конфликта с именами пользователей, [14] но более обычное имя atomicможет быть использовано, если <stdatomic.h>включен заголовок. Из них, constявляется, безусловно, самым известным и наиболее используемым, появляющимся в стандартной библиотеке и встречающимся при любом значительном использовании языка C, который должен удовлетворять константной корректности . Другие квалификаторы используются для низкоуровневого программирования, и хотя широко используются там, редко используются типичными программистами. [ необходима цитата ]

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

Ссылки

  1. ^ Барр, Майкл (2 декабря 2007 г.). "Переносимые целые числа фиксированной ширины в C" . Получено 18 января 2016 г.
  2. ^ ab спецификация ISO/IEC 9899:1999, TC3 (PDF) . стр. 255, § 7.18 Целочисленные типы <stdint.h> .
  3. ^ abcdefghij Спецификация ISO/IEC 9899:1999, TC3 (PDF) . стр. 22, § 5.2.4.2.1 Размеры целочисленных типов <limits.h> .
  4. ^ Обоснование международного стандарта — Языки программирования — C, редакция 5.10 (PDF) . стр. 25, § 5.2.4.2.1 Размеры целочисленных типов <limits.h> .
  5. ^ Проект спецификации ISO/IEC 9899:2023 (PDF) . стр. 41, § 6.2.6 Представления типов .
  6. ^ «Пределы целых чисел в C и C++». 21 июля 2023 г.
  7. ^ ab ISO/IEC 9899:1999 спецификация, TC3 (PDF) . стр. 37, § 6.2.6.1 Представления типов – Общие положения .
  8. ^ abcdef Спецификация ISO/IEC 9899:1999, TC3 (PDF) . стр. 56, § 6.4.4.1 Целочисленные константы .
  9. ^ "64-битные модели программирования: почему LP64?". The Open Group . Получено 9 ноября 2011 г.
  10. ^ «Ширина шрифта (библиотека GNU C)». www.gnu.org . Получено 30 июля 2022 г. .
  11. ^ "<limits.h>". pubs.opengroup.org . Получено 30 июля 2022 г. .
  12. ^ Спецификация ISO/IEC 9899:1999, TC3 (PDF) . стр. 67, § 6.5 Выражения .
  13. ^ Проект спецификации ISO/IEC 9899:2023 (PDF) . стр. 37, § 6.2.5 Типы .
  14. ^ C11: Новый стандарт языка Си, Томас Плам