Скільки памяті займають типи даних C++

0 Comments

Типы данных в С++

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

Целочисленные типы данных

Целочисленные типы данных представляют целые числа. Они могут быть знаковыми или беззнаковыми, а также могут иметь разные размеры в памяти. Наиболее распространенными типами являются int , short , long и long long . Пример использования целочисленных типов данных в С++:

int a = 10; long b = 20; short c = 30; long long d = 40; 

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

Вещественные типы данных

Вещественные типы данных представляют действительные числа. Наиболее распространенными типами являются float и double . Пример использования вещественных типов данных в С++:

float a = 10.5; double b = 20.5; 

Неправильное использование вещественных типов данных может привести к потере точности при вычислениях.

Логические типы данных

Логические типы данных представляют логические значения true или false . Они используются для проверки условий в программе. Наиболее распространенным типом является bool . Пример использования логических типов данных в С++:

bool a = true; bool b = false; 

Символьные типы данных

Символьные типы данных представляют одиночные символы. Наиболее распространенным типом является char . Пример использования символьных типов данных в С++:

char a = 'A'; char b = 'B'; 

Строковые типы данных

Строковые типы данных представляют последовательность символов. Наиболее распространенным типом является string . Пример использования строковых типов данных в С++:

string a = "Hello"; string b = "World"; 

Массивы

Массивы представляют последовательность данных одного типа. Пример использования массивов в С++:

int a[10] = ; float b[5] = ; 

Заключение

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

Размер и диапазон значений различных типов данных могут варьироваться в зависимости от платформы и компилятора.

При выполнении операций с разными типами данных может произойти неявное приведение типов данных, что может привести к потере точности или переполнению.

При работе со строками в С++ можно использовать стандартный тип данных std::string, который предоставляет множество удобных методов для работы со строками.

При работе с массивами в С++ можно использовать стандартный тип данных std::array, который представляет собой статический массив фиксированного размера.

В языке С++ можно создавать пользовательские типы данных с помощью объявления структур или классов.

Хорошей практикой при работе с типами данных является явное приведение типов данных в тех случаях, когда это необходимо, чтобы избежать неявных преобразований типов данных.

Скільки памяті займають типи даних C++

Каждая переменная имеет определенный тип. И этот тип определяет, какие значения может иметь переменная, какие операции с ней можно производить и сколько байт в памяти она будет занимать. В языке C++ определены следующие базовые типы данных: логический тип bool , целочисленные типы, типа чисел с плавающей точкой, символьные типы. Рассмотрим эти группы по отдельности.

Логический тип

Логический тип bool может хранить одно из двух значений: true (истинно, верно) и false (неверно, ложно). Например, определим пару переменных данного типа и выведем их значения на консоль:

#include int main() < bool isAlive ; bool isDead ; std::cout

При выводе значения типа bool преобразуются в 1 (если true) и 0 (если false). Как правило, данный тип применяется преимущество в условных выражениях, которые будут далее рассмотрены.

Значение по умолчанию для переменных этого типа – false .

Целочисленные типы

Целые числа в языке C++ представлены следующими типами:

  • signed char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от -128 до 127
  • unsigned char : представляет один символ. Занимает в памяти 1 байт (8 бит). Может хранить любой значение из диапазона от 0 до 255
  • char : представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255 Несмотря на то, что данный тип представляет тот же диапазон значений, что и вышеописанный тип signed char , но они не эквивалентны. Тип char предназначен для хранения числового кода символа и в реальности может представлять как signed byte , так и unsigned byte в зависимости от конкретного компилятора.
  • short : представляет целое число в диапазоне от –32768 до 32767. Занимает в памяти 2 байта (16 бит). Данный тип также имеет псевдонимы short int , signed short int , signed short .
  • unsigned short : представляет целое число в диапазоне от 0 до 65535. Занимает в памяти 2 байта (16 бит). Данный тип также имеет синоним unsigned short int .
  • int : представляет целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита). Диапазон предельных значений соответственно также может варьироваться от –32768 до 32767 (при 2 байтах) или от −2 147 483 648 до 2 147 483 647 (при 4 байтах). Но в любом случае размер должен быть больше или равен размеру типа short и меньше или равен размеру типа long Данный тип имеет псевдонимы signed int и signed .
  • unsigned int : представляет положительное целое число. В зависимости от архитектуры процессора может занимать 2 байта (16 бит) или 4 байта (32 бита), и из-за этого диапазон предельных значений может меняться: от 0 до 65535 (для 2 байт), либо от 0 до 4 294 967 295 (для 4 байт). Имеет псевдоним unsigned
  • long : в зависимости от архитектуры может занимать 4 или 8 байт и представляет целое число в диапазоне от −2 147 483 648 до 2 147 483 647 (при 4 байтах) или от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807 (при 8 байтах). Занимает в памяти 4 байта (32 бита) или. Имеет псевдонимы long int , signed long int и signed long
  • unsigned long : представляет целое число в диапазоне от 0 до 4 294 967 295. Занимает в памяти 4 байта (32 бита). Имеет синоним unsigned long int .
  • long long : представляет целое число в диапазоне от −9 223 372 036 854 775 808 до +9 223 372 036 854 775 807. Занимает в памяти 8 байт (64 бита). Имеет псевдонимы long long int , signed long long int и signed long long .
  • unsigned long long : представляет целое число в диапазоне от 0 до 18 446 744 073 709 551 615. Занимает в памяти, как правило, 8 байт (64 бита). Имеет псевдоним unsigned long long int .

Для представления чисел в С++ применятся целочисленные литералы со знаком или без, типа -10 или 10. Например, определим ряд переменных целочисленных типов и выведем их значения на консоль:

#include int main() < signed char num1< -64 >; unsigned char num2< 64 >; short num3< -88 >; unsigned short num4< 88 >; int num5< -1024 >; unsigned int num6< 1024 >; long num7< -2048 >; unsigned long num8< 2048 >; long long num9< -4096 >; unsigned long long num10< 4096 >; std::cout u или U. Литералы типов long и long long имеют суффиксы L/l и LL/ll соответственно:

#include int main() < unsigned int num6< 1024U >; // U - unsigned int long num7< -2048L >; // L - long unsigned long num8< 2048UL >; // UL - unsigned long long long num9< -4096LL >; // LL - long long unsigned long long num10< 4096ULL >;// ULL - unsigned long long std::cout #include int main() < int num< 1'234'567'890 >; std::cout 

Различные системы исчисления

По умолчанию все стандартные целочисленные литералы представляют числа в привычной нам десятичной системе. Однако C++ также позволяет использовать и числа в других системах исчисления.

Чтобы указать, что число - шестнадцатеричное, перед числом указывается префикс 0x или 0X . Например:

int num1< 0x1A>; // 26 - в десятичной int num2< 0xFF >; // 255 - в десятичной int num3< 0xFFFFFF >; //16777215 - в десятичной

Чтобы указать, что число - восьмеричное, перед числом указывается ноль 0 . Например:

int num1< 034>; // 26 - в десятичной int num2< 0377 >; // 255 - в десятичной

Бинарные литералы предваряются префиксом 0b или 0B :

int num1< 0b11010>; // 26 - в десятичной int num2< 0b11111111 >; // 255 - в десятичной

Все эти типы литералов также поддерживают суффиксы U/L/LL :

unsigned int num1< 0b11010U>; // 26 - в десятичной long num2< 0377L >; // 255 - в десятичной unsigned long num3< 0xFFFFFFULL >; //16777215 - в десятичной

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

Для хранения дробных чисел в C++ применяются числа с плавающей точкой. Число с плавающей точкой состоит из двух частей: мантиссы и показателя степени . Оба могут быть как положительными, так и отрицательными. Величина числа – это мантисса, умноженная на десять в степени экспоненты.

Например, число 365 может быть записано в виде числа с плавающей точкой следующим образом:

В качестве разделителя целой и дробной частей используется символ точки. Мантисса здесь имеет семь десятичных цифр - 3.650000 , показатель степени - две цифры 02 . Буква E означает экспоненту, после нее указывается показатель степени (степени десяти), на которую умножается часть 3.650000 (мантисса), чтобы получить требуемое значение. То есть, чтобы вернуться к обычному десятичному представлению, нужно выполнить следующую операцию:

3.650000 × 102 = 365

Другой пример - возьмем небольшое число:

В данном случае мы имеем дело с числом –3.65 × 10 -3 , что равно –0.00365 . Здесь мы видим, что в зависимости от значения показателя степени десятичная точка "плавает". Собственно поэтому их и называют числами с плавающей точкой.

Однако хотя такая запись позволяет определить очень большой диапазон чисел, не все эти числа могут быть представлены с полной точностью; числа с плавающей запятой в целом являются приблизительными представления точного числа. Например, число 1254311179 выглядело бы так: 1.254311E09 . Однако если перейти к десятичной записи, то это будет 1254311000 . А это не то же самое, что и 1254311179 , поскольку мы потеряли три младших разряда.

В языке C++ есть три типа для представления чисел с плавающей точкой:

  • float : представляет вещественное число одинарной точности с плавающей точкой в диапазоне +/- 3.4E-38 до 3.4E+38. В памяти занимает 4 байта (32 бита)
  • double : представляет вещественное число двойной точности с плавающей точкой в диапазоне +/- 1.7E-308 до 1.7E+308. В памяти занимает 8 байт (64 бита)
  • long double : представляет вещественное число двойной точности с плавающей точкой не менее 8 байт (64 бит). В зависимости от размера занимаемой памяти может отличаться диапазон допустимых значений.

В своем внутреннем бинарном представлении каждое число с плавающей запятой состоит из одного бита знака, за которым следует фиксированное количество битов для показателя степени и набор битов для хранения мантиссы. В числах float 1 бит предназначен для хранения знака, 8 бит для экспоненты и 23 для мантиссы, что в сумме дает 32 бита. Мантисса позволяет определить точность числа в виде 7 десятичных знаков.

В числах double : 1 знаковый бит, 11 бит для экспоненты и 52 бит для мантиссы, то есть в сумме 64 бита. 52-разрядная мантисса позволяет определить точность до 16 десятичных знаков.

Для типа long double расклад зависит от конкретного компилятора и реализации этого типа данных. Большинство компиляторов предоставляют точность до 18 - 19 десятичных знаков (64-битная мантисса), в других же (как например, в Microsoft Visual C++) long double аналогичен типу double .

В C++ литералы чисел с плавающими точками представлены дробными числами, которые в качестве разделителя целой и дробной частей применяют точку:

Даже если переменной присваивается целое число, чтобы показать, что мы присваиваем число с плавающей точкой, применяется точка:

double num1< 1 >; // 1 - целочисленный литерал double num2< 1. >; //1. - литерал числа с плавающей точкой

Так, здесь число 1. представляет литерал числа с плавающей точкой, и в принципе аналогичен 1.0 .

По умолчанию все такие числа с точкой расцениваются как числа типа double. Чтобы показать, что число представляет другой тип, для float применяется суффикс f / F , а для long double - l / L :

float num1< 10.56f >; // float long double num2< 10.56l >; // long double

В качестве альтернативы также можно применять экспоненциальную запись:

double num1< 5E3 >; // 5E3 = 5000.0 double num2< 2.5e-3 >; // 2.5e-3 = 0.0025

Размеры типов данных

При перечислении типов данных указывался размер, который он занимает в памяти. Но стандарт языка устанавливает лишь минимальные значения, которые должны быть. Например, для типов int и short минимальное значение - 16 бит, для типа long - 32 бита, для типа long double - 64 разряда. При этом размер типа long должен быть не меньше размера типа int, а размер типа int - не меньше размера типа short, а размер типа long double должен быть не меньше double . А разработчики компиляторов могут выбирать предельные размеры для типов самостоятельно, исходя из аппаратных возможностей компьютера.

К примеру, компилятор g++ Windows для long double использует 16 байт. А компилятор в Visual Studio, который также работает под Windows, и clang++ под Windows для long double используют 8 байт. То есть даже в рамках одной платформы разные компиляторы могут по разному подходить к размерам некоторых типов данных. Но в целом используются те размеры, которые указаны выше при описании типов данных.

Однако бывают ситуации, когда необходимо точно знать размер определенного типа. И для этого в С++ есть оператор sizeof() , который возвращает размер памяти в байтах, которую занимает переменная:

#include int main() < long double number ; std::cout 
sizeof(number) = 16

Символьные типы

В C++ есть следующие символьные типы данных:

  • char : представляет один символ в кодировке ASCII. Занимает в памяти 1 байт (8 бит). Может хранить любое значение из диапазона от -128 до 127, либо от 0 до 255
  • wchar_t : представляет расширенный символ. На Windows занимает в памяти 2 байта (16 бит), на Linux - 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 65 535 (при 2 байтах), либо от 0 до 4 294 967 295 (для 4 байт)
  • char8_t : представляет один символ в кодировке Unicode. Занимает в памяти 1 байт. Может хранить любой значение из диапазона от 0 до 256
  • char16_t : представляет один символ в кодировке Unicode. Занимает в памяти 2 байта (16 бит). Может хранить любой значение из диапазона от 0 до 65 535
  • char32_t : представляет один символ в кодировке Unicode. Занимает в памяти 4 байта (32 бита). Может хранить любой значение из диапазона от 0 до 4 294 967 295

char

Переменная типа char хранит числовой код одного символа и занимает один байт. Стандарт языка С++ не определяет кодировку символов, которая будет использоваться для символов char, поэтому производители компиляторов могут выбирать любую кодировку, но обычно это ASCII.

В качестве значения переменная типа char может принимать один символ в одинарных кавычках, либо числовой код символа:

#include int main() < char a1 ; char a2 ; std::cout

В данном случае переменные a1 и a2 будут иметь одно и то же значение, так как 65 - это числовой код символа "A" в таблице ASCII. При выводе на консоль с помощью cout по умолчанию отображается символ.

Кроме того, в C++ можно использовать специальные управляющие последовательности, которые предваряются слешем и которые интерпретируются особым образом. Например, "\n" представляет перевод строки, а "\t" - табуляцию.

Однако ASCII обычно подходит для наборов символов языков, которые используют латиницу. Но если необходимо работать с символами для нескольких языков одновременно или с символами языков, отличных от английского, 256-символьных кодов может быть недостаточно. И в этом случае применяется Unicode .

Unicode (Юникод) — это стандарт, который определяет набор символов и их кодовых точек, а также несколько различных кодировок для этих кодовых точек. Наиболее часто используемые кодировки: UTF-8, UTF-16 и UTF-32. Разница между ними заключается в том, как представлена кодовая точка символа; числовое же значение кода для любого символа остается одним и тем же в любой из кодировок. Основные отличия:

  • UTF-8 представляет символ как последовательность переменной длины от одного до четырех байт. Набор символов ASCII появляется в UTF-8 как однобайтовые коды, которые имеют те же значения кодов, что и в ASCII. UTF-8 на сегодняшний день является самой популярной кодировкой Unicode.
  • UTF-16 представляет символы как одно или два 16-битных значения.
  • UTF-32 представляет все символы как 32-битные значения

В C++ есть четыре типа для хранения символов Unicode: wchar_t , char8_t , char16_t и char32_t ( char16_t и char32_t были добавлены в C+11, а char8_t - в C++20).

wchar_t

Тип wchar_t — это основной тип, предназначенный для наборов символов, размер которых выходит за пределы одного байта. Собственно отсюда и его название: wchar_t - wide (широкий) char. происходит от широкого символа, потому что этот символ «шире», чем обычный однобайтовый символ. Значения wchar_t определяются также как и символы char за тем исключением, что они предваряются символов "L":

Также можно передать код символа

Значение, заключенное в одинарные кавычки, представляет собой шестнадцатеричный код символа. Обратная косая черта указывает на начало управляющей последовательности, а x после обратной косой черты означает, что код шестнадцатеричный.

Стоит учитывать, что для вывода на консоль символов wchar_t следует использовать не std::cout , а поток std::wcout :

#include int main() < char h = 'H'; wchar_t i ; std::wcout

При этом поток std::wcout может работать как с char, так и с wchar_t. А поток std::cout для переменной wchar_t вместо символа будет выводить его числовой код.

Проблема с типом wchar_t заключается в том, что его размер сильно зависит от реализации и применяемой кодировки. Кодировка обычно соответствует предпочтительной кодировке целевой платформы. Так, для Windows wchar_t обычно имеет ширину 16 бит и кодируется с помощью UTF-16. Большинство других платформ устанавливают размер в 32 бита, а в качестве кодировки применяют UTF-32. С одной стороны, это позволяет больше соответствовать конкретной платформе. Но с другой стороны, затрудняет написание кода, переносимого на разные платформы. Поэтому в общем случае часто рекомендуется использовать типы char8_t , char16_t и char32_t . Значения этих типов предназначены для хранения символов в кодировке UTF-8, UTF-16 или UTF-32 соответственно, а их размеры одинаковы на всех распространенных платформах.

Для определения символов типов char8_t , char16_t и char32_t применяются соответственно префиксы u8, u и U:

char8_t c< u8'l' >; char16_t d< u'l' >; char32_t e< U'o' >;

Стоит отметить, что для вывода на консоль значений char8_t/char16_t/char32_t пока нет встроенных инструментов типа std:cout/std:wcout .

Спецификатор auto

Иногда бывает трудно определить тип выражения. В этом случае можно предоставить компилятору самому выводить тип объекта. И для этого применяется спецификатор auto . При этом если мы определяем переменную со спецификатором auto, эта переменная должна быть обязательно инициализирована каким-либо значением:

auto number = 5; // number имеет тип int auto sum ; // sum имеет тип double auto distance ; // distance имеет тип unsigned long

На основании присвоенного значения компилятор выведет тип переменной. Неинициализированные переменные со спецификатором auto не допускаются: