Статьи

Учебные материалы по языку C++ — от основ до продвинутых тем

Типы данных и константы

Страница 7 из 43 · 2026-10-25 · 11 мин чтения

Типы данных и константы в C++

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

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

int health = 100;double speed = 4.5;bool isAlive = true;

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

Основные категории типов данных

Типы данных C++ можно условно разделить на несколько категорий:

  • Целочисленные — хранят целые числа.
  • С плавающей точкой — хранят приближённые значения с дробной частью.
  • Символьные — предназначены для хранения символов и кодовых единиц.
  • Логические — представляют истину или ложь.
  • Составные и пользовательские — позволяют объединять данные или создавать собственные типы.

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

Целочисленные типы используются для хранения значений без дробной части. Они различаются диапазоном представимых значений.

ТипНазначение
shortЦелые числа с небольшим диапазоном
intУниверсальный тип для целых чисел
longЦелые числа с диапазоном не меньше, чем у int
long longЦелые числа с диапазоном не меньше, чем у long
unsigned intНеотрицательные целые числа

Точный размер типов зависит от реализации компилятора и платформы. Для проверки размера в байтах можно использовать оператор sizeof.

#include <iostream>int main() {    std::cout << sizeof(short) << '\n';    std::cout << sizeof(int) << '\n';    std::cout << sizeof(long) << '\n';    std::cout << sizeof(long long) << '\n';    return 0;}

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

Знаковые и беззнаковые числа

Знаковые целочисленные типы, например int, могут хранить отрицательные и положительные значения. Беззнаковые типы, например unsigned int, предназначены для неотрицательных значений.

int temperature = -15;unsigned int playerCount = 20;

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

unsigned int count = 0;count--;std::cout << count << '\n';

В этом примере значение станет максимальным представимым значением типа unsigned int, а не -1.

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

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

Для хранения дробных чисел в C++ используются float, double и long double.

ТипОсобенности
floatОбычно занимает 4 байта, имеет меньшую точность
doubleОбычно занимает 8 байт, подходит для большинства вычислений
long doubleТочность и размер зависят от платформы

Пример:

float playerSpeed = 4.5f;double distance = 125.75;long double preciseValue = 3.141592653589793L;

Суффикс f обозначает литерал типа float, а L — литерал типа long double.

Почему дробные числа могут быть неточными

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

#include <iostream>int main() {    double value = 0.1 + 0.2;    std::cout << value << '\n';    return 0;}

В зависимости от формата вывода результат может отображаться как 0.3 или как близкое к нему значение с дополнительными цифрами.

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

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

Тип bool имеет только два значения:

  • true — истина;
  • false — ложь.

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

bool isConnected = true;bool isPaused = false;if (isConnected) {    // Выполняется, если соединение установлено.}

При выводе через std::cout логические значения по умолчанию отображаются как 1 и 0. Чтобы получить слова true и false, можно использовать std::boolalpha.

#include <iostream>int main() {    bool isReady = true;    std::cout << std::boolalpha << isReady << '\n';    return 0;}

Вывод:

true

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

В C++ есть несколько типов для хранения символов и кодовых единиц:

  • char — базовый символьный тип, также используемый для представления отдельных байтов;
  • wchar_t — тип для широких символов, размер и применение которого зависят от реализации;
  • char8_t — тип для кодовых единиц UTF-8;
  • char16_t — тип для кодовых единиц UTF-16;
  • char32_t — тип для кодовых единиц UTF-32.

Для обычных символьных литералов часто используется char.

char grade = 'A';char operation = '+';

Символ записывается в одинарных кавычках, а строковый литерал — в двойных.

char letter = 'A';const char* text = "Hello";

Типы char8_t, char16_t и char32_t полезны при работе с соответствующими форматами кодирования. При этом один символ Unicode может занимать несколько кодовых единиц, например в UTF-8.

Строки

Для работы с текстом в стандартной библиотеке C++ обычно используется std::string.

#include <iostream>#include <string>int main() {    std::string username = "Alex";    std::cout << "Привет, " << username << "!\n";    return 0;}

Для использования std::string необходимо подключить заголовок <string>.

Строку можно изменять после создания:

std::string message = "Hello";message += ", world!";

После выполнения этих строк переменная message содержит Hello, world!.

Автоматическое определение типа с auto

Ключевое слово auto позволяет компилятору определить тип переменной по её инициализатору.

auto age = 18;       // intauto speed = 4.5;    // doubleauto isActive = true; // bool

Это удобно, когда тип очевиден из выражения или имеет сложное написание.

При использовании auto тип всё равно определяется на этапе компиляции — это не динамическая типизация.

auto count = 10;count = 20;     // Допустимо// count = 3.14; // Для int дробная часть потеряется при преобразовании

Если переменная уже имеет тип int, присваивание ей другого числового типа не меняет тип самой переменной.

Преобразование типов

Иногда необходимо преобразовать значение из одного типа в другой.

Неявное преобразование

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

int value = 10;double result = value;

Здесь целое число преобразуется в double. В данном случае значение 10 представляется точно.

При обратном преобразовании возможна потеря информации:

double value = 9.8;int result = value;std::cout << result << '\n';

Результат:

9

При преобразовании такого значения в int дробная часть отбрасывается.

Явное преобразование

Чтобы явно указать преобразование, можно использовать static_cast.

double value = 9.8;int result = static_cast<int>(value);

Такой способ помогает показать намерение программиста и делает преобразование заметным в коде. При этом static_cast не предотвращает потерю дробной части или другие последствия преобразования.

Что такое константа

Константа — это значение, которое после инициализации нельзя изменить через соответствующий объект или объявление.

В C++ для этого часто используются const и constexpr.

Константы с const

Ключевое слово const запрещает изменять объект через имя, объявленное с этим квалификатором.

const int maxHealth = 100;const double gravity = 9.81;

Попытка присвоить новое значение такой переменной приведёт к ошибке компиляции:

const int maxHealth = 100;// maxHealth = 200; // Ошибка компиляции

Константа должна получить значение при инициализации. Это полезно для настроек, фиксированных параметров и значений, которые не должны случайно меняться.

Константные выражения с constexpr

Ключевое слово constexpr предназначено для значений и функций, которые могут участвовать в вычислениях на этапе компиляции при соблюдении требований языка.

constexpr int windowWidth = 1280;constexpr int windowHeight = 720;constexpr int pixelCount = windowWidth * windowHeight;

Поскольку значения известны во время компиляции, компилятор может вычислить pixelCount заранее.

В отличие от обычного const, constexpr требует, чтобы переменная была пригодна для использования в константном выражении.

int getValue() {    return 10;}int main() {    const int runtimeValue = getValue();    constexpr int compileTimeValue = 10;    return 0;}

В этом примере runtimeValue является константой, но её значение определяется при выполнении программы. compileTimeValue — константное выражение, известное при компиляции.

Разница между const и constexpr

Свойствоconstconstexpr
Запрещает изменение объекта через это имяДаДа
Значение обязательно известно при компиляцииНетДа, для переменной
Подходит для значения, полученного во время выполненияДаНет, если оно не является константным выражением
Может использоваться для константных выраженийЕсли значение удовлетворяет требованиям языкаДа

Используй const, когда значение нельзя изменять, а constexpr — когда оно должно быть доступно как константа времени компиляции.

Константы и указатели

При работе с указателями важно различать константный объект и константный указатель.

int value = 10;int otherValue = 20;const int* ptr = &value;ptr = &otherValue; // Можно изменить адрес// *ptr = 30;      // Нельзя изменить значение через ptr

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

int value = 10;int* const ptr = &value;*ptr = 30; // Можно изменить значение// ptr = nullptr; // Нельзя изменить сам указатель

int* const — константный указатель на изменяемый int. Его адрес нельзя изменить после инициализации, но объект можно изменять через указатель.

const int* const ptr = &value;

В этом случае нельзя изменить ни адрес указателя, ни значение объекта через этот указатель.

Пользовательские типы данных

C++ позволяет создавать собственные типы, объединяя данные или задавая новые правила их представления.

Например, struct позволяет объединить связанные значения:

struct Player {    int health;    double speed;};int main() {    Player player{100, 4.5};    return 0;}

Здесь Player — пользовательский тип, содержащий здоровье и скорость игрока. Переменная player хранит объект этого типа.

Также можно создавать перечисления с помощью enum class:

enum class GameState {    Menu,    Playing,    Paused,    GameOver};GameState state = GameState::Playing;

Перечисления удобны для состояний и наборов именованных вариантов, а enum class помогает избежать неявного преобразования значений перечисления в целые числа.

Пример: типы данных и константы вместе

В следующем примере используются целые числа, дробные значения, строки, логические переменные и константы.

#include <iostream>#include <string>int main() {    const std::string playerName = "Alex";    constexpr int maxHealth = 100;    int health = maxHealth;    double speed = 4.5;    bool isAlive = true;    health -= 25;    isAlive = health > 0;    std::cout << "Игрок: " << playerName << '\n';    std::cout << "Здоровье: " << health << '/' << maxHealth << '\n';    std::cout << "Скорость: " << speed << '\n';    std::cout << "Жив: " << std::boolalpha << isAlive << '\n';    return 0;}

Вывод:

Игрок: AlexЗдоровье: 75/100Скорость: 4.5Жив: true

maxHealth — константа времени компиляции, а playerName — строка, которую программа не должна изменять. Значения health, speed и isAlive могут изменяться во время выполнения программы.

Частые ошибки

Выход за диапазон типа

int value = 2147483647;value++;

Если операция со знаковым целым числом выходит за представимый диапазон, возникает неопределённое поведение. Не следует полагаться на переполнение знаковых типов.

Потеря дробной части

int result = static_cast<int>(5.9);

Значение result будет равно 5. Если дробная часть важна, используй подходящий тип, например double.

Попытка изменить константу

const int maxPlayers = 10;// maxPlayers = 20; // Ошибка компиляции

Если значение должно меняться, не объявляй его как const.

Использование constexpr для значения времени выполнения

int readValue();int main() {    // constexpr int value = readValue(); // Ошибка, если результат не является константным выражением    return 0;}

Для значения, которое определяется во время выполнения, обычно подходит обычная переменная или const.

Итог

  • Тип данных определяет представление значения и допустимые операции.
  • int, float, double, bool, char и std::string решают разные задачи хранения.
  • Размеры некоторых встроенных типов зависят от платформы и реализации компилятора.
  • auto позволяет компилятору вывести тип из инициализатора.
  • Преобразование типов может приводить к потере данных, поэтому важно учитывать его последствия.
  • const запрещает изменение объекта через соответствующее объявление.
  • constexpr используется для значений, которые должны быть константными выражениями.
  • struct и enum class помогают создавать собственные типы для организации данных.