Тип данных — это характеристика переменной, которая задает допустимые значения, операции над ними и объем памяти под хранение. Типизация — правила языка, по которым тип назначается переменной и проверяется. Разберем, какие типы данных встречаются чаще всего, чем статическая типизация отличается от динамической, а сильная от слабой, и как это выглядит в коде на C, C++, Python и JavaScript.
Содержание
- Мини-словарь: термины, которые часто путают
- Два независимых измерения типизации
- Основные встроенные типы данных
- Целочисленные типы: диапазоны зависят от платформы
- Числа с плавающей точкой
- Строки, символы и логический тип
- Явная и неявная типизация на примерах
- Выводы
- Где применяется / связь с практикой
- FAQ
Мини-словарь: термины, которые часто путают
Прежде чем сравнивать языки, разведем понятия, которые легко смешать в одну шкалу.
- Тип данных — конкретный вид значений (int, string, bool) с набором допустимых операций.
- Типизация — правила языка, по которым тип назначается и проверяется.
- Статическая типизация — тип фиксируется при компиляции и не меняется.
- Динамическая типизация — тип определяется во время выполнения и может смениться при переприсваивании.
- Сильная / слабая типизация — отдельная ось: разрешает ли язык неявно превращать одно значение в другое.
Дальше будет видно, что это две независимые оси, а не синонимы одной шкалы «строгости».
Два независимых измерения типизации
Частая ошибка — считать, что «строгий» язык проверяет типы при компиляции, а «гибкий» — только во время исполнения. На деле это разные оси: когда проверяется тип (статическая типизация — при компиляции, динамическая — при выполнении) и насколько широко разрешено смешивать типы без явного преобразования (сильная или слабая типизация).
| Язык | Когда проверяется тип | Неявные преобразования между несовместимыми типами |
|---|---|---|
| C++ | Статическая (при компиляции) | Ограничены, в основном между числовыми типами |
| C | Статическая (при компиляции) | Разрешены шире, чем в C++ |
| Python | Динамическая (при выполнении) | Не допускаются для несовместимых типов |
| JavaScript | Динамическая (при выполнении) | Допускаются широко, например "5" + 3 дает "53" |
C++ — статически и в целом сильно типизированный язык. Python — динамически, но сильно типизированный: строку и число нельзя сложить без явного преобразования, ошибка будет во время выполнения. JavaScript — динамически и слабо типизированный: он попробует привести типы сам.
Основные встроенные типы данных
К базовым типам, которые встречаются почти в любом языке программирования, относят:
| Тип | Что хранит | Пример значения |
|---|---|---|
| Целочисленный (int) | целые числа | 42, -7 |
| С плавающей точкой (float, double) | дробные числа | 3.14 |
| Строковый (string) | последовательность символов | «otus» |
| Логический (bool) | одно из двух значений | true, false |
| Символьный (char) | один символ и его код | ‘a’ |
Дальше — подробнее про целые числа, дробные числа и границы, которые зависят от платформы.
Целочисленные типы: диапазоны зависят от платформы
Стандарты C и C++ задают только минимальный размер целочисленных типов — реальный размер зависит от платформы и компилятора, то есть от модели данных.
На практике используют две модели: LP64 (Linux, macOS — long занимает 8 байт) и LLP64 (64-битный Windows — long остается 4 байта, 8 байт только у long long). Код, жестко рассчитанный на размер long, при переносе между Linux и Windows может считать неверно.
| Тип | Типичный размер (Linux/macOS, LP64) | Типичный размер (Windows, LLP64) | Диапазон при 32 битах, со знаком |
|---|---|---|---|
| short | 2 байта | 2 байта | от -32 768 до 32 767 |
| int | 4 байта | 4 байта | от -2 147 483 648 до 2 147 483 647 |
| long | 8 байт | 4 байта | зависит от фактического размера |
| long long | 8 байт | 8 байт | от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 |
Точный размер для своей платформы лучше проверять через sizeof(), а не полагаться на таблицу из статьи:
#include <iostream>
int main() {
std::cout << "char: " << sizeof(char) << " byte\n";
std::cout << "short: " << sizeof(short) << " bytes\n";
std::cout << "int: " << sizeof(int) << " bytes\n";
std::cout << "long: " << sizeof(long) << " bytes\n";
std::cout << "long long: " << sizeof(long long) << " bytes\n";
return 0;
}
Вывод на 64-битном Linux (GCC 13, модель LP64):
char: 1 byte
short: 2 bytes
int: 4 bytes
long: 8 bytes
long long: 8 bytes
На 64-битном Windows (MSVC, модель LLP64) строка long выведет 4 bytes — это не ошибка компилятора, а разница моделей данных.
Числа с плавающей точкой
Дробные числа в большинстве языков хранятся по стандарту IEEE 754. Точность и размер зависят от конкретного типа:
- float — обычно 32 бита (4 байта), около 7 значащих десятичных цифр.
- double — обычно 64 бита (8 байт), около 15-16 значащих цифр.
- long double — размер платформозависим: на GCC или Clang для 32-битного x86 это 80-битное расширенное представление в 12 байтах, для x86-64 — те же 80 бит данных, но выровненные до 16 байт; в MSVC на Windows long double по факту равен double (64 бита). На конкретный размер long double в переносимом коде полагаться нельзя.
В языках уровня приложений вроде C# отдельно есть тип decimal — десятичная арифметика с фиксированным размером 128 бит и точностью около 28-29 значащих цифр. В T-SQL тоже есть decimal/numeric, но это другая реализация: precision задается вручную (от 1 до 38 значащих цифр), а под капотом это 5-17 байт в зависимости от заданной precision, а не фиксированные 128 бит — размеры C# и T-SQL decimal путать нельзя. В C и C++ встроенного decimal нет, его берут из библиотек — для точных денежных расчетов, а не скорости.
Строки, символы и логический тип
Строковый тип хранит последовательность символов, обычно в кавычках. В C++ есть низкоуровневый char* или массив char и более удобный std::string из стандартной библиотеки. В Python и JavaScript строка — готовый неизменяемый объект языка.
Символьный тип (char) хранит один символ вместе с его кодом по таблице кодирования. В C и C++ char занимает 1 байт и обычно соответствует ASCII или первым 256 значениям кодировки. Для символов вне ASCII, например кириллицы или эмодзи, байта недостаточно — в C++ есть wchar_t, char8_t, char16_t и char32_t, и размер части из них тоже платформозависим: wchar_t занимает 2 байта на Windows и 4 байта на Linux/macOS. Как код символа превращается в байты, подробно разобрано в статье о кодировках в компьютерах.
Логический тип (bool) хранит одно из двух значений — true или false. В C++ при выводе в консоль bool отображается как 1 или 0, а не как слово. Значение bool без инициализации на уровне функции не определено стандартом — гарантированный false есть только у глобальных и статических переменных, которые обнуляются автоматически.
Явная и неявная типизация на примерах
Отдельно от строгости и момента проверки стоит явность типа — пишет ли программист имя типа сам, или язык выводит его из значения. Это третье измерение, не синоним статической или динамической типизации.
В C++ есть явное объявление и вывод типа через auto — тип фиксируется статически, просто программист не написал его словом:
#include <iostream>
int main() {
auto x = 5; // компилятор выводит int
auto y = 5.0; // компилятор выводит double
std::cout << x << " " << y << "\n";
return 0;
}
Вывод: 5 5.
В Python тип вообще не объявляется — он всегда определяется присвоенным значением, и может смениться при следующем присвоении:
x = 10
print(type(x))
x = "hello"
print(type(x))
Вывод:
<class 'int'>
<class 'str'>
При этом Python не разрешит сложить число и строку без явного преобразования — это и есть сильная типизация:
x = 5
y = "5"
print(x + y)
Фактический результат:
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Исправление — явно привести типы: print(x + int(y)) даст 10. В слабо типизированном JavaScript тот же код отработает без ошибки: 5 + "5" даст строку "55".
Выводы
- Тип данных — это допустимые значения, операции и объем памяти; типизация — правила языка по их назначению и проверке.
- Статическая/динамическая (когда проверяется тип) и сильная/слабая (насколько строго проверяется) — независимые оси, их нельзя сводить к одной шкале.
- Размеры целочисленных и вещественных типов зависят от платформы и компилятора (модели LP64/LLP64, реализация IEEE 754); точный размер проверяют через
sizeof(). - Явное указание типа и вывод типа (auto в C++, отсутствие объявления в Python) — тоже отдельное измерение, не совпадающее со статической или динамической типизацией.
Где применяется / связь с практикой
Понимание типов данных нужно в любой практической разработке — от объявления переменных до дизайна структур данных и API. Переполнение int, неявное приведение и потеря точности float — частая причина багов, которые сложно найти без понимания типизации.
Освойте тему на практике
Разобрать типы данных и типизацию на практике, с реальными задачами и обратной связью преподавателей, можно на курсе Python Basic — там же встретится динамическая и сильная типизация Python на практике.
Освойте тему на практике
Если пока не готовы к полному курсу, можно начать с открытых уроков Otus — там разбирают конкретные темы бесплатно, в формате живого занятия.
Смежные темы: Все о кодировках в компьютерах.
FAQ
Можно ли в одном языке сочетать статическую и динамическую типизацию?
Да, это называется постепенной типизацией: TypeScript добавляет статические проверки поверх динамического JavaScript, а Python поддерживает необязательные type hints для линтеров вроде mypy.
Что происходит при переполнении целочисленного типа в C++?
Для беззнаковых типов переполнение — арифметика по модулю степени двойки, значение просто «оборачивается». Для знаковых, например int, переполнение — неопределенное поведение, рассчитывать на конкретный результат нельзя.
Почему сравнивать дробные числа на точное равенство считается ошибкой?
float и double хранят дробные числа приближенно из-за двоичного представления, поэтому 0.1 + 0.2 в большинстве языков не равно ровно 0.3. Для сравнения используют допустимую погрешность, а не оператор ==.



