Тип данных в C и C++ — это свойство переменной, которое задает, какие значения она может хранить, сколько памяти под нее выделяется и какие операции с ней разрешены. Оба языка статически и строго типизированы: тип указывают при объявлении, и он не меняется во время работы программы.
Содержание
Ниже разберем базовые типы семейства C (char, int, float, double, bool), как узнать их размер через sizeof, чем отличаются знаковые и беззнаковые целые, и зачем нужны enum, void и типы фиксированной ширины. Все примеры прогнаны и выводы в тексте — реальные (компилятор Clang, 64-битная сборка, macOS/Linux, проверено 17.09.2026).
Семейство C: где действуют эти типы
Речь о языках C и C++. Их система базовых типов почти совпадает: C++ вырос из C и сохранил его числовые типы, добавив свои (например, bool и строгие перечисления). Родственные Objective-C и C# синтаксически похожи, но их типы устроены иначе, и здесь мы их не рассматриваем.
Поэтому дальше все примеры даны на C и C++, и там, где поведение языков расходится, это отмечено отдельно.
Базовые типы данных
Базовые (встроенные) типы — те, что понимает сам компилятор без подключения библиотек. Их удобно держать в одной таблице: по ней видно, что и сколько занимает.
| Тип | Обычный размер | Что хранит | Типичный диапазон |
|---|---|---|---|
char |
1 байт | символ или маленькое целое | -128..127 либо 0..255 |
short |
2 байта | короткое целое | -32 768..32 767 |
int |
4 байта | целое общего назначения | -2 147 483 648..2 147 483 647 |
long |
4 или 8 байт | большое целое | зависит от платформы |
long long |
8 байт | очень большое целое | примерно +-9,2 * 10^18 |
float |
4 байта | дробное, ~6-7 значащих цифр | примерно +-3,4 * 10^38 |
double |
8 байт | дробное, ~15-16 значащих цифр | примерно +-1,8 * 10^308 |
bool |
1 байт | true или false |
только два значения |
Важна оговорка о размерах: стандарт C и C++ не фиксирует их жестко, а задает лишь минимумы и соотношения (char <= short <= int <= long). Приведенные числа верны для распространенных 64-битных компиляторов, но long, например, занимает 8 байт на Linux и macOS и 4 байта на Windows. Поэтому размер всегда лучше не запоминать, а измерять — об этом следующий раздел.
Коротко про отдельные типы:
charхранит один байт. Его чаще всего используют для символов в кодировке ASCII, но по сути это целое число, и его можно складывать и сравнивать.int— целочисленный тип по умолчанию, им объявляют счетчики и обычные числа.floatиdoubleхранят дробные числа с плавающей точкой.double(двойная точность) точнее и потому используется по умолчанию для вещественных вычислений.bool— логический тип из C++, принимает толькоtrueилиfalse. В чистом C для него есть_Boolи заголовок<stdbool.h>.
Размер типа и оператор sizeof
Чтобы не гадать, сколько байт занимает тип на конкретной машине, есть оператор sizeof. Он возвращает размер в байтах и вычисляется на этапе компиляции. Вот полная программа на C, которую можно скопировать и запустить:
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main(void) {
printf("char: %zu byte, %d..%d\n", sizeof(char), CHAR_MIN, CHAR_MAX);
printf("int: %zu bytes, %d..%d\n", sizeof(int), INT_MIN, INT_MAX);
printf("long: %zu bytes\n", sizeof(long));
printf("float: %zu bytes, ~%d значащих цифр\n", sizeof(float), FLT_DIG);
printf("double: %zu bytes, ~%d значащих цифр\n", sizeof(double), DBL_DIG);
return 0;
}
Вывод программы:
char: 1 byte, -128..127
int: 4 bytes, -2147483648..2147483647
long: 8 bytes
float: 4 bytes, ~6 значащих цифр
double: 8 bytes, ~15 значащих цифр
Диапазоны здесь взяты не наугад: макросы INT_MIN, INT_MAX из <limits.h> и FLT_DIG, DBL_DIG из <float.h> знают точные границы для текущего компилятора. Это надежнее, чем держать числа в голове.
Обратите внимание на строку char: здесь он оказался знаковым (-128..127), но знаковость char стандартом не задана и на некоторых платформах он беззнаковый (0..255). Если знак важен, пишут явно signed char или unsigned char.
Знаковые и беззнаковые целые
У каждого целого типа есть две версии: знаковая (signed, по умолчанию) хранит и отрицательные, и положительные числа, беззнаковая (unsigned) — только неотрицательные, зато вдвое больший положительный предел. Например, unsigned int вмещает 0..4 294 967 295 вместо -2 147 483 648..2 147 483 647 у int.
Здесь легко поймать ошибку. Беззнаковые не умеют быть отрицательными: при вычитании ниже нуля результат не уходит в минус, а заворачивается к максимальному значению. И при сравнении знакового с беззнаковым знаковое молча превращается в беззнаковое. Покажем это на C++:
#include <iostream>
using namespace std;
int main() {
unsigned int u = 0;
u = u - 1; // 0 - 1 в беззнаковом типе
cout << "u = " << u << "\n";
int a = 3, b = 5; // a - b = -2
unsigned int c = 10;
cout << "a - b = " << (a - b) << "\n";
cout << "(a - b) < c ? " << ((a - b) < c) << "\n"; // ждем 1, получаем 0
return 0;
}
Фактический вывод:
u = 4294967295
a - b = -2
(a - b) < c ? 0
Разберем сюрприз в последней строке. Само по себе a - b равно -2, это видно во второй строке вывода. Но в сравнении (a - b) < c слева знаковое число, справа беззнаковое c, поэтому -2 приводится к unsigned и становится тем самым 4 294 967 295. Оно больше 10, и результат сравнения — 0 (ложь), хотя по смыслу -2 меньше 10.
Исправление простое: не смешивать знаковое и беззнаковое в одном сравнении. Здесь достаточно объявить c как int, и (a - b) < c вернет ожидаемую 1. Общий совет — для обычной арифметики брать знаковый int, а unsigned использовать осознанно (битовые маски, размеры контейнеров), помня про заворот.
Перечисления и void
Кроме базовых чисел, в семействе C есть еще два типа, которые часто встречаются новичкам.
Перечисление (enum) — это набор именованных целочисленных констант. Оно делает код читаемее: вместо чисел 0, 1, 2 пишут понятные имена. По умолчанию первая константа равна 0, каждая следующая на единицу больше.
void — это «отсутствие типа». Он не хранит значение и применяется в трех ролях: функция ничего не возвращает (void f()), у функции нет параметров (в C пишут int f(void)), либо как «указатель на что угодно» (void*).
Заодно посмотрим на типы фиксированной ширины из заголовка <cstdint> (в C — <stdint.h>). В отличие от int, чей размер плавает между платформами, int32_t гарантированно занимает ровно 4 байта везде, а int8_t — один. Это удобно, когда важен точный размер: сетевые протоколы, форматы файлов, работа с оборудованием.
#include <iostream>
#include <cstdint>
using namespace std;
enum Level { LOW, MEDIUM, HIGH }; // 0, 1, 2
int main() {
Level l = MEDIUM;
cout << "MEDIUM = " << l << "\n";
cout << "int8_t: " << sizeof(int8_t) << " byte\n";
cout << "int32_t: " << sizeof(int32_t) << " bytes\n";
cout << "int64_t: " << sizeof(int64_t) << " bytes\n";
bool flag = true;
cout << "bool: " << sizeof(flag) << " byte, value " << flag << "\n";
return 0;
}
Вывод программы:
MEDIUM = 1
int8_t: 1 byte
int32_t: 4 bytes
int64_t: 8 bytes
bool: 1 byte, value 1
MEDIUM действительно равен 1 (вторая по счету константа), а bool при выводе печатается как 1 для true и 0 для false. Размеры int8_t, int32_t, int64_t совпадают с числом в имени и не зависят от платформы — в этом их смысл.
Как выбрать тип под задачу
Короткий ориентир, а не полный каталог:
- Целое общего назначения (счетчики, индексы, обычные числа) —
int. - Число больше двух миллиардов —
long long(илиint64_t). - Дробное число, деньги-суммы для расчетов —
double;floatберут ради экономии памяти в больших массивах. - Один символ или байт —
char; текст — массивcharилиstd::stringв C++. - Логический флаг —
bool(C++). - Точный размер поля в байтах — типы из
<cstdint>(int32_tи подобные).
Общее правило: берите самый простой тип, которого хватает по диапазону, и не смешивайте знаковые с беззнаковыми в одном выражении.
Выводы
- Тип данных в C и C++ задает набор возможных значений, размер в памяти и допустимые операции; тип фиксируется при объявлении и не меняется.
- Базовые типы: целые (
char,short,int,long,long long), дробные (float,double) и логическийbool; их размеры стандарт задает не жестко, а через минимумы и соотношения. - Размер типа надежнее измерять оператором
sizeof, а границы брать из<limits.h>/<float.h>, а не запоминать. - Знаковые и беззнаковые целые нельзя бездумно смешивать: беззнаковое вычитание заворачивается, а в сравнении знаковое приводится к беззнаковому.
- Для точного размера поля берут типы фиксированной ширины из
<cstdint>.
Где применяется и что учить дальше
Понимание типов данных — это фундамент любой программы на C или C++: от него зависят и корректность вычислений, и расход памяти, и скорость. Ошибка в выборе типа (переполнение int, потеря точности float, заворот unsigned) — одна из самых частых причин трудноуловимых багов, поэтому тему разбирают одной из первых.
Освойте тему на практике
Если хочется освоить C++ системно — от типов и указателей до классов и работы с памятью — посмотрите курс C++ Developer. Basic. Оценить формат и уровень до старта помогают бесплатные открытые уроки Otus — живые занятия с преподавателями.
Смежные темы: Структуры и типы данных, Кодировка данных: кириллица, Языки программирования: характеристика, описание, виды.
FAQ
Чем float отличается от double, если оба дробные? Разрядностью и точностью: float занимает 4 байта и хранит около 6-7 значащих цифр, double — 8 байт и около 15-16. Для расчетов по умолчанию берут double, float — когда критична экономия памяти.
Почему sizeof(char) всегда равен 1, а размеры других типов измеряют в этих единицах? По стандарту sizeof(char) равен 1 по определению — это «единица измерения» памяти в C и C++. Размеры остальных типов выражаются в таких же единицах, то есть в числе байт, занимаемых одним char.
Можно ли хранить в char русскую букву? Одна кириллическая буква в кодировке UTF-8 занимает два байта, а char — это один байт, поэтому целиком она в один char не помещается. Русский текст хранят в массиве char (последовательности байт) или в строковом типе.



