- Изучение C++ в Linux. Типы данных.
- Целочисленные
- Остальные целочисленные типы
- short int
- long int
- Типы с плавающей точкой или дробные типы
- Float
- Double
- Вся правда о целочисленных типах в C
- Про signed и unsigned
- О размере unsigned char
- Размеры целочисленных типов в С
- Новые типы в С99
- Unsigned long int size linux
- Unsigned long int size linux
Изучение C++ в Linux. Типы данных.
С++ является типизированным языком программирования, где переменные, функции и их аргументы необходимо явно задавать. Так как язык является расширяемым, то типов данных может огромное множество, мы рассмотрим только основные.
В предыдущей статье, я коротко об этом упоминал, но давайте попробуем разобраться какие типы данных есть в языке C++:
- — void
- — целочисленные
- — с плавающей запятой
Типом void можно считать пустоту, то есть данный тип ничего не возвращает и не хранит. Данный тип нельзя использовать для объявления переменных. Как правило, данный тип используется для объявления функций, которые ничего не возвращают. Например:
Как видим из этого примера, у нас есть функция test(), которая имеет тип void. Единственное что делает данная функция, так это вывод текст на экран. Если вы попытаетесь сделать возвращение каких либо данных (return 0; return true; или return), то компилятор вернет ошибку. Но можно использовать следующую конструкцию:
В данном примере, мы сделали возвращение пустого return; что бы завершить выполнение данной функции.
Целочисленные
Целочисленные типы хранят в себе, как понятно из названия, целые числа.
Данный тип используется для хранения символов. Для Char отводиться в системе 1 байт (8 бит), что дает возможность закодировать 256 символов ASCII.
Вначале мы объявили переменную character с типом char, мы записали туда только одну букву, обратите внимание на кавычки, я использовал одинарные, это указывает системе, что тут один символ, если использовать двойные кавычки — будет ошибка. Если попытаться написать туда что-то еще, кроме буквы Z, то компилятор выдаст ошибку.
Вторая переменная charArr уже имеет [], что указывает, что я буду использовать строковой массив данных, и кавычки уже двойные. По сути текст: «Привет мир!» это массив из 11 символов.
По-этому если вам нужно использовать какой то текст, в котором больше чем 1 символ, вам нужно использовать строковой массив char charArr[] и двойные кавычки.
Тип данных Bool так же является целочисленным, но используется для логических операций, значение которое он может принимать от 0 до 255. 0 является значением false (ложь), а 1 и больше true (правдой)
Переменная Check — является типом bool, которой присвоено значение false (0 или ложь), дальше мы делаем довольно абсурдную конструкцию с точки программирования, но это сделано ради примера, так как код
Конструкцию return (nNCelsius > 10); можно представить так
Остальные целочисленные типы
Вместе с целочисленными типами можно использовать специальные модификаторы
- unsigned — значение будет идти без отрицательных чисел
- signed — значение может быть как положительным, так и отрицательным
short int
Целое число, небольшого диапазона, занимающая всего 2 байта в памяти. Short int может принимать значения от -32 768 до 32 767. Если добавить модификатор unsigned то значение будет от 0 до 65 535
Обратите внимание, что выдаст программа если превышено значение принимаемого значения? Да, будет -32768, мы получим самый крайний отрицательный результат, для данного типа. Тоже актуально и для остальных целочисленных типов!
Целое число, для данного типа выделяется 4 байта памяти. Int имеет значения от -2 147 483 648 до 2 147 483 647. Если добавить unsigned, то значение будет от 0 до 4 294 967 295
long int
Данный тип занимает 8 байта и имеет значения от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807, а unsigned long int от 0 до 18 446 744 073 709 551 615
Типы с плавающей точкой или дробные типы
В С++ существует 2 типа, позволяющие записывать числа с плавающей точкой — float и double
Float
Данный тип занимает 4 байта, и может иметь значения от -2 147 483 648.0 до 2 147 483 647.0
Double
Данный тип занимает 8 байта, и может иметь значения от -9 223 372 036 854 775 808 .0 до 9 223 372 036 854 775 807.0
В C++ есть еще такой тип как перечисления (enum) его я рассмотрю в следующих статьях.
Вся правда о целочисленных типах в C
Для начала несколько вопросов:
- Тип char по умолчанию знаковый или нет? А int ?
- Законно ли неявное приведение (signed char *) к (char *) ? А то же для int ?
- Сколько бит в unsigned char ?
- Какое максимальное число гарантированно можно поместить в int ? А минимальное?
- Тип long определённо больше, чем char , не так ли?
Разумеется, экспериментально искать ответы на эти вопросы с помощью вашего любимого компилятора в вашей любимой системе на вашем любимом компьютере 1) — не лучшая идея. Мы говорим о стандарте языка (С99 и новее).
Если вы уверенно сможете правильно ответить на эти вопросы, тогда эта статья не для вас. В противном случае десять минут, потраченные на её чтение, будут весьма полезны.
- Знаковые оба.
- Законны оба.
- 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)
Стандарт требует, чтобы максимальное значение unsigned char было 2 CHAR_BIT −1 (см. предыдущий пункт).
Стандарт требует sizeof(char) . Таким образом, вполне законны ситуации типа 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 long int size linux
Переменная имеет определенный тип. И этот тип определяет, какие значения может иметь переменная и сколько байт в памяти она будет занимать. В Си определены следующие базовые типы данных:
char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от -128 до 127
unsigned char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от 0 до 255
signed char : то же самое, что и char
short int : представляет целое число в диапазоне от –32768 до 32767. Занимает в памяти 2 байта (16 бит).
short : то же самое, что и short int .
unsigned short int : представляет целое число в диапазоне от 0 до 65535. Занимает в памяти 2 байта (16 бит).
unsigned short : то же самое, что и unsigned short int .
signed short int : то же самое, что и short int .
signed short : то же самое, что и short int .
int : представляет целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита). Диапазон предельных значений соответственно также может варьироваться от –32768 до 32767 (при 2 байтах) или от −2 147 483 648 до 2 147 483 647 (при 4 байтах).
unsigned int : представляет положительное целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита), и из-за этого диапазон предельных значений может меняться: от 0 до 65535 (для 2 байт), либо от 0 до 4 294 967 295 (для 4 байт).
unsigned : то же самое, что и unsigned int
signed int : то же самое, что и int
signed : то же самое, что и int
long int : представляет целое число в диапазоне от −2 147 483 648 до 2 147 483 647. Занимает в памяти 4 байта (32 бита).
long : то же самое, что и long int .
signed long int : то же самое, что и long int .
signed long : то же самое, что и long int .
unsigned long int : представляет целое число в диапазоне от 0 до 4 294 967 295. Занимает в памяти 4 байта (32 бита).
unsigned long : то же самое, что и unsigned long int .
long long int : представляет целое число в диапазоне от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807. Занимает в памяти, как правило, 8 байт (64 бита).
long long : то же самое, что и long long int .
signed long long int : то же самое, что и long long int
signed long long : то же самое, что и long long int .
unsigned long long int : представляет целое число в диапазоне от 0 до 18 446 744 073 709 551 615. Занимает в памяти, как правило, 8 байт (64 бита).
unsigned long long : то же самое, что и unsigned long long int .
float : представляет вещественное число ординарной точности с плавающей точкой в диапазоне +/- 3.4E-38 до 3.4E+38. В памяти занимает 4 байта (32 бита)
double : представляет вещественное число двойной точности с плавающей точкой в диапазоне +/- 1.7E-308 до 1.7E+308. В памяти занимает 8 байт (64 бита)
long double : представляет вещественное число двойной точности с плавающей точкой в диапазоне +/- 3.4E-4932 до 1.1E+4932. В памяти занимает 10 байт (80 бит). На некоторых системах может занимать 96 и 128 бит.
void : тип без значения
Определим несколько переменных:
Если нам надо определить несколько переменных одного типа, то мы можем указать их названия после типа данных через запятую: int a, b
Переменная типа char в качестве значения принимает один символ в одинарных кавычках: char c =’d’ . Также можно присвоить число из указанного выше в списке диапазона: char c = 120 . В этом случае значением переменной c будет тот символ, который имеет код 120 в таблице символов ASCII.
В выше приведенном списке для каждого типа указан размер, который он занимает в памяти. Однако стоит отметить, что предельные размеры для типов разработчики компиляторов могут выбирать самостоятельно, исходя из аппаратных возможностей компьютера. Стандарт устанавливает лишь минимальные значения, которые должны быть. Например, для типов int и short минимальное значение — 16 бит, для типа long — 32 бита. При этом размер типа long должен быть не меньше размера типа int, а размер типа int — не меньше размера типа short. Но в целом для типов используются те размеры, которые указаны выше при описании типов данных.
Однако бывают ситуации, когда необходимо точно знать размер определенного типа. И для этого в C есть оператор sizeof() , который возвращает размер памяти в байтах, которую занимает переменная:
При этом при определении переменных важно понимать, что значение переменной не должно выходить за те пределы, которые очерчены для ее типа. Например:
Компилятор GCC при компиляции программы с этой строкой выдаст ошибку о том, что значение -65535 не входит в диапазон допустимых значений для типа unsigned short int.
Но как видно из перечисления типов, ряд из них, например, int , может содержать разные значения в зависимости от платформы. В этом случае мы можем получить минимально и максимально допустимые значения с помощью встроенных значений INT_MIN и INT_MAX :
Unsigned long int size linux
Q: How big is an int, long int etc. in C?
A: It depends. (The standard leaves it completely up to the compiler, which also means the same compiler can make it depend on options and target architecture.)
In practice I have not used anything else but gcc on Linux for a couple of years, so for myself the answer is a bit easier. However, because I don’t program C/C++ that often these days, each time I do so I soon tend to hit the question how big was that integer again, especially if interfacing with some low-level stuff and the code should work correctly on both 32 bit and 64 bit machines. At the moment I mostly use Intel architecture, so let me limit this post to Intel. (I have used a lot of ARM in the past and this week glibc with support for AArch64 came out, maybe the results can be checked against ARM later.)
type \ executable[1] | 32 bit | 64 bit |
short int | 16 bit | 16 bit |
int | 32 bit | 32 bit |
long int | 32 bit | 64 bit |
long long int | 64 bit | 64 bit |
size_t | 32 bit | 64 bit |
void* [2] | 32 bit | 64 bit |
[1] A 32 bit executable can be used in a 64 bit user space (supposed a 32 bit loader and required shared libraries have been installed), a 32 bit user space can run on a 64 bit kernel and a 32 bit kernel can run on a 64 bit processor. So it’s really the word length of the executable that counts.
[2] In exotic cases pointers can have different lengths, http://stackoverflow.com/questions/6751749/size-of-a-pointer So, I’m not sure whether sizeof (void *) isn’t in fact undefined by the C standard. At least gcc compiles it without warning and returns a value, which looks correct for gcc on the Intel systems covered here.
The results where produced by the following piece of code:
Slightly related the code also shows 2 features for 32/64 bit portable usage of printf. The “z” length modifier refers to size_t, see printf(3) for a couple of similar ones. The PRIu32 macro makes sure that a constant word length is used regardless of the compiler specific length of the integer types. This and several similar macros are in fact standardized in C99, they are defined in header inttypes.h .