JavaRush /Курсы /C++ SELF /Базовые типы в C++: int, long, unsigned, char

Базовые типы в C++: int, long, unsigned, char

C++ SELF
6 уровень , 2 лекция
Открыта

1. Введение

Когда человек только начинает программировать, он часто мыслит так: «мне же просто надо хранить значения, почему нельзя сделать один универсальный тип number и не мучиться?». Это нормально: мозг экономит энергию. Но C++ — язык, который любит конкретику. Тип в C++ — это не “украшение”, а договор: сколько памяти нужно, какие значения допустимы, как работает ввод/вывод и какие операции вообще имеют смысл.

Представьте, что вы храните данные в разных коробках. Для печенья — коробка с крышкой, для супа — кастрюля, для воздуха —… ну, воздух не хранится, он просто уходит, как мотивация в пятницу вечером. Типы — это как разные “контейнеры”, и если вы попытаетесь налить суп в коробку от печенья, результат будет предсказуемо грустным.

Сегодня мы разберём пять базовых типов, которые встречаются постоянно:

  • int — обычные целые числа со знаком,
  • long long — целые числа побольше,
  • unsigned — целые числа без минуса,
  • double — дробный тип,
  • char — один символ.

И параллельно введём очень важную идею: диапазон значений (границы того, что тип способен хранить).

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

В отличии от многих языков программирования, целочисленные типы в C++ не имеют фиксированного размера. Это сделано для того, чтобы компилятор мог максимально совместить машинный код программы и платформу (ОС+процессор).

Одну и ту же программу на C++ можно скомпилировать под 16, 32, и 64 разрядные процессоры; под macOS, Windows, Linux и т.п. А у них у всех целочисленные типы данных разные (так исторически сложилось).

Изначально в C++ было 3 целых типа:

  • int - целый тип
  • short int (он же short) - коротки целый тип (1/2 длинны int)
  • long int (он же long) - длинный целый тип (2 длинны int)

Но потом добавили еще более длинный целый - long long int, он же long long.

Сейчас их "стандартные" длины выглядят так:

Тип Windows x64 macOS x64
short
2 байта 2 байта
int
4 байта 4 байта
long
4 байта 8 байт
long long
8 байт 8 байт

Вместо типа long лучше использовать тип long long - он гарантированной больше чем int.

Как выбирать тип под задачу

Очень хочется выбирать тип по принципу “какой короче пишется” или “какой я видел в примерах”. Но в реальном коде тип — часть смысла. Если вы видите в коде bool isAdmin, вы почти без комментариев понимаете, что там только два состояния. Если вы видите char grade, вы ожидаете букву вроде 'A' или 'B'. А вот если всё сделать int, то получится “свалка”: 0 может означать “нет”, “ошибка”, “не найдено”, “первый элемент” или “ещё ничего не вводили”.

2. Целочисленные типы: int, long long, unsigned

int: базовый рабочий “кирпич” для целых чисел

int — это самый частый целочисленный тип, с которого обычно начинают. Когда вы считаете количество задач, номер дня, счётчик в цикле, температуру в градусах (если без дробей), баланс очков в игре — почти всегда достаточно int.

Важно понимать две вещи. Первая: int хранит целые числа и умеет хранить минус. Вторая: int не бесконечный — у него есть границы, и это ключ к пониманию “диапазонов”. Но про диапазоны — чуть ниже; пока работаем как практики: int — “нормальный выбор по умолчанию” для целых значений разумного размера.

Мини-фрагмент для нашего StudyBuddy:

#include <iostream>

int main() {
    int tasksSolvedToday = 0;
    std::cin >> tasksSolvedToday;

    std::cout << tasksSolvedToday << '\n'; // например: 7
}

Здесь tasksSolvedToday — это “количество”, и оно по смыслу целое. Уже на этом шаге тип помогает: невозможно случайно записать туда “3.14” как дробь — компилятор будет против (и это хорошо).

long long: когда значения действительно большие

Почти в каждом проекте наступает момент, когда обычного int становится мало. Обычно это происходит не сразу, а когда вы начинаете накапливать значения: суммарное количество секунд за год, общее число просмотров, общий объём данных, итоговые очки за сезон, количество операций в логах — то есть всё, что может вырасти значительно больше, чем “обычная цифра на входе”.

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

Добавим в StudyBuddy “накопленный итог задач” (пусть пользователь введёт, сколько задач он решил “за всё время”, а программа посчитает новый итог):

#include <iostream>

int main() {
    long long totalTasksBefore = 0;
    int tasksToday = 0;

    std::cin >> totalTasksBefore >> tasksToday;
    long long totalAfter = totalTasksBefore + tasksToday;

    std::cout << totalAfter << '\n'; // например: 1050
}

Обратите внимание на мысль: вход “за день” может быть маленьким, но итог — большой. Это очень частый паттерн, и он не про “умение писать формулы”, а про корректный выбор типа.

unsigned: “без минуса” как часть договора

Любой целочисленный тип в С++ можно сделать беззнаковым (положительным), если добавить перед ним ключевое слово unsigned. Тип unsigned int (часто пишут просто unsigned) означает: “целое число без отрицательных значений”. То есть диапазон unsigned смещается в сторону больших положительных чисел, потому что место под минус не требуется.

Звучит идеально для “количеств”: количество задач, количество пользователей, количество попыток. Но есть важный практический момент: в реальном коде минус иногда нужен не потому что “в жизни бывает -5 задач”, а потому что минус используют как сигнал (например, “ошибка” или “не найдено”). Мы пока не строим такие сложные контракты (это отдельная большая тема), поэтому сейчас правило простое: используйте unsigned только тогда, когда вы уверены, что отрицательные значения по смыслу невозможны и вам не нужен “минус” как специальный сигнал.

В StudyBuddy добавим “сколько дней подряд я учусь” — это хороший кандидат на неотрицательное значение:

#include <iostream>

int main() {
    unsigned streakDays = 0;
    std::cin >> streakDays;

    std::cout << streakDays << '\n'; // например: 12
}

На этом этапе достаточно запомнить: unsigned подчёркивает “неотрицательность” на уровне типа. Но это не “магическая защита от всех бед”, а просто более строгий договор.

3. Типы для “дробей” и “символа”: double и char

double: когда числа бывают с дробной частью

Если int и long long — это про целые значения, то double — это про числа с дробной частью. Как только в задаче появляется что-то вроде среднего значения, процента, коэффициента, температуры с десятыми долями или денежной суммы с копейками — вам уже недостаточно целого типа.

double хранит вещественные числа (числа с плавающей точкой). Это означает, что он умеет представлять значения вроде 3.14, 0.5, -12.75. Но за эту гибкость приходится платить: внутри такие числа хранятся не “идеально точно”, а в двоичном представлении, которое может давать небольшие погрешности.

Добавим в StudyBuddy среднюю продуктивность за неделю:

#include <iostream>

int main() {
    double averageTasksPerDay = 0.0;
    std::cin >> averageTasksPerDay;

    std::cout << averageTasksPerDay << '\n'; // например: 5.75
}

Обратите внимание на 0.0 — это подчёркивает, что мы работаем именно с вещественным числом.

Почему нельзя просто взять int и “делить аккуратно”? Потому что при делении целых чисел дробная часть отбрасывается. Например, 7 / 2 в целых даст 3, а не 3.5. Если вам важна точность результата с дробями, нужен именно double.

Важно также понимать: double — не “бесконечно точный калькулятор”. Например, число 0.1 в двоичной системе не представляется точно, поэтому операции вроде 0.1 + 0.2 могут давать результат 0.30000000000000004. Это не “баг компилятора”, а особенность представления чисел с плавающей точкой.

Практическое правило для новичка:

  • если вы считаете целые количества (штуки, дни, элементы) — используйте int или long long;
  • если вы считаете средние значения, проценты, коэффициенты, дроби — используйте double.

Тип double — это договор: “здесь возможны дробные значения”. И, как и в случае с другими типами, он помогает сделать код понятнее уже на уровне объявления переменной.

char: один символ и разница между 'A' и "A"

char — это тип для хранения одного символа. Он пишется в одинарных кавычках: 'A', '?', '7'. Это принципиально отличается от строки "A" (строка — это текст, потенциально из многих символов, и мы её уже знаем как std::string).

Очень полезная привычка новичка: когда видите одинарные кавычки — думайте “один символ”. Когда двойные — “строка/текст”.

В StudyBuddy мы попросим у пользователя ввести “оценку продуктивности” одной буквой, например A, B, C:

#include <iostream>

int main() {
    char grade = 'C';
    std::cin >> grade;

    std::cout << grade << '\n'; // например: A
}

char хорошо подходит, когда данные действительно “однобуквенные”: код ответа Y/N, оценка A/B/C, команда q для выхода, разделитель, один символ категории.

Внутри тип char просто хранит код символа и по сути является целочисленным типом. В C++ с ним можно проводить математические операции.

5. Диапазоны значений

Теперь самая важная философская часть сегодняшней лекции — но мы сделаем её максимально практичной.

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

В быту это похоже на счётчик километража в старых машинах: он не бесконечный. Когда цифры заканчиваются, он “переворачивается” (а иногда просто ломается). С типами примерно та же идея: если число выходит за границы, поведение становится неправильным. Мы не будем сейчас разбирать тонкости “как именно неправильно” (это отдельная тема), но вам важно уже сегодня привыкнуть к мысли: тип выбирают так, чтобы значение точно помещалось.

Чтобы было удобнее ориентироваться, вот практическая табличка “как это обычно выглядит на современных системах”. Это не обещание “везде так”, а здравый ориентир для мышления:

Тип Что хранит Пример диапазона значений
bool
true/false
false / true (0 или 1)
char
один символ −128 … 127
int
целые со знаком −2 147 483 648 … 2 147 483 647
unsigned
целые без знака 0 … 4 294 967 295
long long
большие целые со знаком −9 223 372 036 854 775 808 … 9 223 372 036 854 775 807
double
дробные со знаком примерно ±1.7 × 10308 (с ~15 знаками точности)

Идея, которую стоит унести: если вы делаете “итог”, “общее количество”, “накопленную сумму”, “число секунд за долгий период”, то чаще всего это кандидат на long long. Если вы храните “флаг” или “да/нет”, то это bool. Если “одна буква/команда”, это char.

6. Размеры типов и sizeof

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

Для этого существует оператор sizeof. Он возвращает размер типа или переменной в байтах.

Простейший пример:

#include <iostream>

int main() {
    std::cout << sizeof(int) << '\n';
    std::cout << sizeof(long long) << '\n';
    std::cout << sizeof(double) << '\n';
    std::cout << sizeof(char) << '\n';
}

Вы можете получить, например:

4
8
8
1

Это означает:

  • int занимает 4 байта
  • long long — 8 байт
  • double — 8 байт
  • char — 1 байт

7. Типичные ошибки при выборе базовых типов

Ошибка №1: хранить логические состояния в int и плодить “магические числа”.
Новичок часто делает int ok = 1;, int ok = 0;, а потом в другом месте внезапно пишет if (ok == 2). Проблема тут не в том, что компилятор не поймёт, а в том, что человек перестаёт понимать. Если у состояния ровно два варианта, bool сообщает это прямо в типе и не даёт вам “случайно” сделать третье состояние.

Ошибка №2: использовать char как “короткую строку”.
Иногда хочется хранить текст "OK" или "Hi" в char, потому что “ну это же всего два символа”. Но char — это ровно один символ. Если вам нужен текст, даже из двух букв, это уже строка (std::string). Очень полезно каждый раз ловить себя на вопросе: “мне нужен один знак или текст?”.

Ошибка №3: выбирать unsigned “потому что количество же не бывает отрицательным”, а потом всё равно понадобился минус.
Жизнь коварна: сегодня вы храните “количество задач”, а завтра вам нужен сигнал “не введено”, “ошибка”, “не найдено”. И внезапно “минус” становится удобным. На старте лучше не превращать unsigned в религию: используйте его, когда уверены, что отрицательные значения не нужны ни по смыслу, ни как служебный сигнал.

Ошибка №4: хранить накопленные итоги в int, потому что “пока хватает”.
Это классическая ловушка. Пока тестовые данные маленькие — всё красиво. Потом вы делаете итог “за год”, “за всё время”, “для всех пользователей”, и число внезапно перестаёт помещаться. Именно поэтому для итогов и сумм часто заранее берут long long: это дешёвая страховка, которая экономит часы поиска странных багов.

Ошибка №5: думать, что диапазоны — это “какая-то теория”, и игнорировать их совсем.
Диапазоны — это не академическая тема, а прямое следствие того, что память конечна. Если тип не способен хранить нужные значения, программа начинает вести себя неправильно. Даже если вы пока не умеете “вычислять границы в уме”, достаточно привычки задавать себе вопрос: “а это число может стать очень большим?” — и тогда выбирать тип осознанно.

1
Задача
C++ SELF, 6 уровень, 2 лекция
Недоступна
Паспорт типов
Паспорт типов
1
Задача
C++ SELF, 6 уровень, 2 лекция
Недоступна
Ответ согласия
Ответ согласия
1
Задача
C++ SELF, 6 уровень, 2 лекция
Недоступна
Партия товара
Партия товара
1
Задача
C++ SELF, 6 уровень, 2 лекция
Недоступна
Секунды и int
Секунды и int
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ