# Data Types
The header <stdint.h> provides several fixed-width integer type definitions. These types are optional and only provided if the platform has an integer type of the corresponding width, and if the corresponding signed type has a two’s complement representation of negative values.
See the remarks section for usage hints of fixed width types.
# Interpreting Declarations
A distinctive syntactic peculiarity of C is that declarations mirror the use of the declared object as it would be in a normal expression.
The following set of operators with identical precedence and associativity are reused in declarators, namely:
- the unary * "dereference" operator which denotes a pointer;
- the binary [] "array subscription" operator which denotes an array;
- the (1+n)-ary () "function call" operator which denotes a function;
- the () grouping parentheses which override the precedence and associativity of the rest of the listed operators.
The above three operators have the following precedence and associativity:
| Operator | Relative Precedence | Associativity |
|---|---|---|
| [] (array subscription) | 1 | Left-to-right |
| () (function call) | 1 | Left-to-right |
| * (dereference) | 2 | Right-to-left |
When interpreting declarations, one has to start from the identifier outwards and apply the adjacent operators in the correct order as per the above table. Each application of an operator can be substituted with the following English words:
| Expression | Interpretation |
|---|---|
| thing[X] | an array of size X of. |
| thing(t1, t2, t3) | a function taking t1 , t2 , t3 and returning. |
| *thing | a pointer to. |
It follows that the beginning of the English interpretation will always start with the identifier and will end with the type that stands on the left-hand side of the declaration.
# Examples
[] takes precedence over * , so the interpretation is: names is an array of size 20 of a pointer to char .
In case of using parentheses to override the precedence, the * is applied first: place is a pointer to an array of size 10 of char .
There is no precedence to worry about here: fn is a function taking long , short and returning int .
The () is applied first: fn is a function taking void and returning a pointer to int .
Overriding the precedence of () : fp is a pointer to a function taking void and returning int .
Multidimensional arrays are not an exception to the rule; the [] operators are applied in left-to-right order according to the associativity in the table: arr is an array of size 5 of an array of size 8 of int .
The two dereference operators have equal precedence, so the associativity takes effect. The operators are applied in right-to-left order: ptr is a pointer to a pointer to an int .
# Multiple Declarations
The declared objects in the above example are:
- fn : a function taking void and returning int ;
- ptr : a pointer to an int ;
- fp : a pointer to a function taking int and returning int ;
- arr : an array of size 10 of an array of size 20 of int ;
- num : int .
# Alternative Interpretation
Because declarations mirror use, a declaration can also be interpreted in terms of the operators that could be applied over the object and the final resulting type of that expression. The type that stands on the left-hand side is the final result that is yielded after applying all operators.
# Integer types and constants
Signed integers can be of these types (the int after short , or long is optional):
Each of these signed integer types has an unsigned version.
For all types but char the signed version is assumed if the signed or unsigned part is omitted. The type char constitutes a third character type, different from signed char and unsigned char and the signedness (or not) depends on the platform.
Different types of integer constants (called literals in C jargon) can be written in different bases, and different width, based on their prefix or suffix.
Decimal constants are always signed . Hexadecimal constants start with 0x or 0X and octal constants start just with a 0 . The latter two are signed or unsigned depending on whether the value fits into the signed type or not.
Without a suffix the constant has the first type that fits its value, that is a decimal constant that is larger than INT_MAX is of type long if possible, or long long otherwise.
The header file <limits.h> describes the limits of integers as follows. Their implementation-defined values shall be equal or greater in magnitude (absolute value) to those shown below, with the same sign.
| Macro | Type | Value |
|---|---|---|
| CHAR_BIT | smallest object that is not a bit-field (byte) | 8 |
| SCHAR_MIN | signed char | -127 / -(2 7 — 1) |
| SCHAR_MAX | signed char | +127 / 2 7 — 1 |
| UCHAR_MAX | unsigned char | 255 / 2 8 — 1 |
| CHAR_MIN | char | see below |
| CHAR_MAX | char | see below |
| SHRT_MIN | short int | -32767 / -(2 15 — 1) |
| SHRT_MAX | short int | +32767 / 2 15 — 1 |
| USHRT_MAX | unsigned short int | 65535 / 2 16 — 1 |
| INT_MIN | int | -32767 / -(2 15 — 1) |
| INT_MAX | int | +32767 / 2 15 — 1 |
| UINT_MAX | unsigned int | 65535 / 2 16 — 1 |
| LONG_MIN | long int | -2147483647 / -(2 31 — 1) |
| LONG_MAX | long int | +2147483647 / 2 31 — 1 |
| ULONG_MAX | unsigned long int | 4294967295 / 2 32 — 1 |
| Macro | Type | Value |
|---|---|---|
| LLONG_MIN | long long int | -9223372036854775807 / -(2 63 — 1) |
| LLONG_MAX | long long int | +9223372036854775807 / 2 63 — 1 |
| ULLONG_MAX | unsigned long long int | 18446744073709551615 / 2 64 — 1 |
If the value of an object of type char sign-extends when used in an expression, the value of CHAR_MIN shall be the same as that of SCHAR_MIN and the value of CHAR_MAX shall be the same as that of SCHAR_MAX . If the value of an object of type char does not sign-extend when used in an expression, the value of CHAR_MIN shall be 0 and the value of CHAR_MAX shall be the same as that of UCHAR_MAX .
The C99 standard added a new header, <stdint.h> , which contains definitions for fixed width integers. See the fixed width integer example for a more in-depth explanation.
# Floating Point Constants
The C language has three mandatory real floating point types, float , double , and long double .
The header <float.h> defines various limits for floating point operations.
Floating point arithmetic is implementation defined. However, most modern platforms (arm, x86, x86_64, MIPS) use IEEE 754
(opens new window) floating point operations.
C also has three optional complex floating point types that are derived from the above.
# String Literals
A string literal in C is a sequence of chars, terminated by a literal zero.
String literals are not modifiable (and in fact may be placed in read-only memory such as .rodata). Attempting to alter their values results in undefined behaviour.
Multiple string literals are concatenated at compile time, which means you can write construct like these.
String literals, same as character constants, support different character sets.
What is char , unsigned char , and signed char ?
The char type in C , has a size of 1 byte . The size of a byte , as defined on a given machine , can be viewed by checking the macro CHAR_BITS , in the limits.h header .
Typically a byte in C , or on a given machine is formed of 8 bits .
The char type is an integer type , it is used to store the encoding of characters . For example , the encoding of the character a , when a is considered to be part of the ascii character set , is 97 in decimal , or 01100001 in binary . If a is considered to belong to a different character set , it might have a different encoding , as such a variable of the char type , would store a different encoding value for the character a .
The char type can be signed or it can be unsigned , this is implementation defined . The C standard defines , the minimum range that the char type can have , an implementation can define large ranges .
If the char type is unsigned , then it can only contain non negative values , and its minimum range as defined by the C standard is between 0 , and 127 . If the char type is signed , then it can contain 0 , negative , and positive values , and its minimum range as defined by the C standard , is between -127 , and 127 .
Beside the char type in C , there is also the unsigned char , and the signed char types . All three types are different , but they have the same size of 1 byte . The unsigned char type can only store nonnegative integer values , it has a minimum range between 0 and 127 , as defined by the C standard. The signed char type can store , negative , zero , and positive integer values . It has a minimum range between -127 and 127 , as defined by the C standard .
character literals
A character literal , is formed of a character , such as a , enclosed in single quote .
A character literal can contain escape sequences . An escape sequence , is used as a way to represent characters , in the execution character set . For example a new line , that must appear on a console , or on the terminal .
Escape sequences , are also used to represent characters , that cannot appear in character literals , such as single quote , or in string literals , such as double quote .
Escape sequences , are also used to escape the interpretation of some special characters , such as ? .
Escape sequences , are also used , as a way to input characters , by entering their encoding , instead of the character itself .
Escape sequences , can also be used , as a way to enter a character universal name , in this case , the character must be a wide character type .
Since , signed char , unsigned char , and char , and wide characters , are integer types , they can be initialized by using an integer literal . The integer literal in such a case , hold the value of the encoding of the character .
Вся правда о целочисленных типах в C
Если вы уверенно сможете правильно ответить на эти вопросы, тогда эта статья не для вас. В противном случае десять минут, потраченные на её чтение, будут весьма полезны.
- Знаковые оба.
- Законны оба.
- 8.
- 2147483647. -2147483648.
- Конечно, Кэп.
- char — не регламентируется, int — знаковый.
- Для int — законно, а для char — нет.
- Не менее 8.
- 32767. -32767
- Вообще говоря, нет.
Про signed и unsigned
Все целочисленные типы кроме char , по умолчанию знаковые (signed).
С char ситуация сложнее. Стандарт устанавливает три различных типа: char , signed char , unsigned char . В частности, указатель типа (signed char *) не может быть неявно приведён к типу (char *) .
Хотя формально это три разных типа, но фактически char эквивалентен либо signed char , либо unsigned char — на выбор компилятора (стандарт ничего конкретного не требует).
Подробнее про char я написал в комментариях.
О размере unsigned char
Тип unsigned char является абстракцией машинного байта. Важность этого типа проявляется в том, что С может адресовать память только с точностью до байта. На большинстве архитектур размер байта равен 8 бит, но бывают и исключения. Например, процессоры с 36-битной архитектурой как правило имеют 9-битный байт, а в некоторых DSP от Texas Instruments байты состоят из 16 или 32 бит. Древние архитектуры могут иметь короткие байты из 4, 5 или 7 бит.
Стандарт С вынужден отказаться от допотопных архитектур и требует, чтобы байты были как минимум 8-битные. Конкретное значение ( CHAR_BIT 2) ) для данной платформы записано в заголовочном файле limits.h .
Размеры целочисленных типов в С
C переносимый, поэтому в нём базовые целочисленные типы ( char , short , int и др.) не имеют строго установленного размера, а зависят от платформы. Однако эти типы не были бы переносимы, если бы
их размеры были совершенно произвольные: стандарт устанавливает минимальные диапазоны принимаемых значений для всех базовых целочисленные типов. А именно,
- signed char: -127. 127 (не -128. 127; аналогично другие типы)
- unsigned char : 0. 255 (= 2 8 −1)
- signed short : -32767. 32767
- unsigned short : 0. 65535 (= 2 16 −1)
- signed int : -32767. 32767
- unsigned int : 0. 65535 (= 2 16 −1)
- signed long : -2147483647. 2147483647
- unsigned long : 0. 4294967295 (= 2 32 −1)
- signed long long : -9223372036854775807. 9223372036854775807
- unsigned long long : 0. 18446744073709551615 (= 2 64 −1)
Стандарт требует sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long) . Таким образом, вполне законны ситуации типа sizeof(char)=sizeof(long)=32 . Для некоторых DSP от Texas Instruments так и есть.
Конкретные значения этих диапазонов для данной платформы указаны заголовочном файле limits.h .
Новые типы в С99
После того, как C99 добавил тип long long , целочисленных типов и путаницы стало ещё больше. Чтобы навести порядок, стандарт ввёл заголовочный файл stdint.h , где определяются типы вроде int16_t (равно 16 бит), int_least16_t (минимальный тип, способный вместить 16 бит), int_fast16_t (по крайней мере 16 бит, работа с этим типом наиболее быстрая на данной платформе) и т. п.
least- и fast-типы фактически являются заменой рассмотренных выше типов int , short , long и т. п. только вдобавок дают программисту возможность выбора между скоростью и размером.
От типов вроде int16_t , со строгим указанием размера, страдает переносимость: скажем, на архитектуре с 9-битным байтом может просто не найтись 16-битного регистра. Поэтому стандарт тут явно говорит, что эти типы опциональны. Но учитывая, что какой бы код вы ни писали, чуть менее чем во всех случаях целевая архитектура фиксирована даже в худшем случае с точностью до семейства (скажем, x86 или AVR), внутри которого, размер байта не может вдруг поменяться, то переносимость фактически сохраняется. Более того, типы вроде int16_t оказались даже более популярными, чем int_least16_t и int_fast16_t , а при низкоуровневом программировании (микроконтроллеры, драйверы устройств) и подавно, ибо там зачастую неопределённость размера переменной просто непозволительна.
1) Для удобства тройку архитектура+ОС+компилятор далее будем называть просто платформой.
2) Этот макрос правильнее было бы назвать UCHAR_BIT , но по причинам совместимости он называется так, как называется.
Unsigned char c что это
unsigned long long
Определение чисел в различных системах
Си позволяет определять числа в разных числовых системых. Числа в двоичной системе начинаются с символов 0b , после которых идет набор 1 и 0, которые представляют число. Восьмеричные числа начинаются с числа 0, за которым могут идти цифры от 0 до 7. Щестнадцатеричные числа начинаются с 0x или 0X , за которыми следуют шестнадцатеричные цифры от 0 до 9 и от A до F. Например:
В данном случае определены четыре переменных, но каждая из них хранит одно и то же число — 11, записанное в разных системах исчисления.
Числа с плавающей точкой
Числа с плавающей точкой представлены тремя типами: float , double , long double . В качестве разделителя между целой и дробной частями применяется точка. По умолчанию все дробные числа представляют тип double , который занимает 8 байт:
Для вывода значения double на консоль используется спецификаторы f и lf . Чтобы указать, что число представляет тип float , применяется суффикс f , а для long double — суффикс l :
Стоит отметить, что для вывода данных типа long double на консоль применяется спецификатор Lf , однако на некоторых платформах он может работать некорректно, например, показывать 0.
Символы
Переменным типа char можно присвоить один символ в одинарных кавычках:
Здесь определяется переменная letter, которая хранит символ ‘A’. Однако в реальности переменная типа char хранит число. И когда переменной присваивается символ, она получает числовой код этого символа из таблицы, которая сопоставляет числовые коды и символы. Наиболее распространена таблица ASCII. Она сопоставляет символы с числами от 0 до 127. Например, возьмем выше определенную переменную letter и выведем ее содержимое на консоль:
Числовой код символа ‘A’ в таблице ASCII равен 65. Для наглядности в программе два раза выводим значение переменной letter. Но в первом случае используем спецификатор %d для вывода числового кода символа, а во втором случае применяется спецификатор %c , который позволяет вывести на консоль сам символ. То есть при выполнении программа выведет на консоль:
Вместо символа в одинарных кавычках мы могли бы присвоить напрямую числовой код:
И мы получили бы тот же самый результат.
typedef
Оператор typedef позволяет определить для определенного типа псевдоним. Это может потребоваться, например, когда название некоторого типа довольно большое, и мы хотим его сократить.
Общая форма оператора
Например, зададим для типа unsigned char псевдоним BYTE :
И мы сможем использовать этот тип как и любой другой:
Размер типов данных
В выше приведенном списке для каждого типа указан размер, который он занимает в памяти. Однако стоит отметить, что предельные размеры для типов разработчики компиляторов могут выбирать самостоятельно, исходя из аппаратных возможностей компьютера. Стандарт устанавливает лишь минимальные значения, которые должны быть. Например, для типов int и short минимальное значение — 16 бит, для типа long — 32 бита. При этом размер типа long должен быть не меньше размера типа int, а размер типа int — не меньше размера типа short. Но в целом для типов используются те размеры, которые указаны выше при описании типов данных.
Однако бывают ситуации, когда необходимо точно знать размер определенного типа. И для этого в C есть оператор sizeof() , который возвращает размер памяти в байтах, которую занимает переменная:
При этом при определении переменных важно понимать, что значение переменной не должно выходить за те пределы, которые очерчены для ее типа. Например:
Компилятор GCC при компиляции программы с этой строкой выдаст ошибку о том, что значение -65535 не входит в диапазон допустимых значений для типа unsigned short int.
