Тип данных — это классификация, которая задает для значения два свойства: множество допустимых значений (диапазон) и набор операций, которые с ним разрешены. Целочисленный тип int (от integer) хранит целые числа без дробной части и поддерживает арифметику, сравнение и побитовые операции.
Содержание
Ниже разберем, зачем язык вообще делит данные на типы, чем примитивные типы отличаются от ссылочных, как устроена разрядность и диапазоны у int, что такое знаковые и беззнаковые целые, чем грозит переполнение и какие операции доступны над целыми. Примеры на Python и C запущены, вывод в тексте — реальный.
Что такое тип данных
Тип данных отвечает на два вопроса о значении: какие значения допустимы и что с ними можно делать. Например, целое число можно умножать и сравнивать, а к строке умножение обычной арифметики неприменимо.
Благодаря типам компилятор или интерпретатор ловит ошибки заранее и подбирает правильную машинную операцию. Сложение двух целых и сложение двух дробных — это разные инструкции процессора, и тип подсказывает, какую взять.
Диапазон значений у целого типа не бесконечен в языках с фиксированной разрядностью: он определяется числом отведенных бит. Именно поэтому у int есть верхняя и нижняя граница, и о них важно помнить.
Примитивные и ссылочные типы
Типы принято делить на две большие группы. Разница — в том, что хранит переменная: само значение или ссылку на него.
- Примитивные типы встроены в язык и хранят значение напрямую: целые (int), дробные (float, double), логический (bool), символ (char). Целые числа — это как раз примитивный тип.
- Ссылочные (составные) типы хранят ссылку на объект в памяти: строки, массивы, объекты классов, структуры. Их часто определяет сам разработчик.
Это деление заметнее всего в Java и C#, где оно закреплено в языке. В Python формально все является объектами, но целые числа ведут себя как простые значения, и на практике их удобно считать примитивами.
Целочисленный тип int: разрядность и диапазоны
Разрядность int — это число бит, отведенных под целое. От нее напрямую зависит диапазон: n бит со знаком дают значения от минус 2 в степени (n-1) до 2 в степени (n-1) минус 1.
Стандартные ширины целых и их диапазоны одинаковы во всех языках с фиксированной разрядностью:
| Ширина | Со знаком | Без знака | Типичный тип в C/C++ |
|---|---|---|---|
| 8 бит | -128 .. 127 | 0 .. 255 | signed char / unsigned char |
| 16 бит | -32 768 .. 32 767 | 0 .. 65 535 | short |
| 32 бита | -2 147 483 648 .. 2 147 483 647 | 0 .. 4 294 967 295 | int |
| 64 бита | -9,2 * 10^18 .. 9,2 * 10^18 | 0 .. 1,8 * 10^19 | long long |
Для 64 бит точные границы со знаком: от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807; без знака — от 0 до 18 446 744 073 709 551 615.
Важная оговорка: сама ширина типа int зависит от языка и платформы, а не только от названия. В C и C++ стандарт гарантирует лишь минимум 16 бит, но на современных системах int обычно 32-битный. Тип long по стандарту не меньше 32 бит: на 64-битных Linux и macOS он 64-битный, а на 64-битной Windows — 32-битный. Поэтому переносимый код полагается на фиксированные типы вроде int32_t и int64_t из заголовка stdint.h.
int в разных языках
Название int в разных языках означает разное. Полезно держать в голове сводку:
| Язык | Тип int | Разрядность | Беззнаковые целые |
|---|---|---|---|
| C / C++ | int | зависит от платформы, обычно 32 бита (минимум 16) | есть (unsigned) |
| Java | int | всегда 32 бита | нет отдельных типов |
| C# | int | всегда 32 бита (System.Int32) | есть (uint) |
| Python | int | без фиксированной границы (bignum) | не нужны |
Python здесь выделяется: у его int нет заранее заданной разрядности. Число растет по мере надобности и ограничено только памятью, поэтому арифметического переполнения у него не бывает. Проверим это на коде:
# Python: целое произвольной длины (bignum), аппаратного переполнения нет
big = 2 ** 100
print("2**100 =", big)
print("бит в этом числе:", big.bit_length())
# целочисленное деление и остаток (в Python деление округляется вниз)
print("17 // 5 =", 17 // 5, "; 17 % 5 =", 17 % 5)
print("-17 // 5 =", -17 // 5, "; -17 % 5 =", -17 % 5)
# побитовые операции
print("6 & 3 =", 6 & 3, "; 6 | 3 =", 6 | 3, "; 6 ^ 3 =", 6 ^ 3)
print("1 << 10 =", 1 << 10)
# для сравнения - границы int32 и uint32 в C-стиле
print("верх int32:", 2 ** 31 - 1)
print("верх uint32:", 2 ** 32 - 1)
Вывод программы:
2**100 = 1267650600228229401496703205376
бит в этом числе: 101
17 // 5 = 3 ; 17 % 5 = 2
-17 // 5 = -4 ; -17 % 5 = 3
6 & 3 = 2 ; 6 | 3 = 7 ; 6 ^ 3 = 5
1 << 10 = 1024
верх int32: 2147483647
верх uint32: 4294967295
Число 2 в степени 100 заняло 101 бит — в 32-битный int оно бы не поместилось, а Python держит его целиком. Обратите внимание на деление минус 17 на 5: Python округляет частное вниз (к минус бесконечности), поэтому остаток получается положительным. В C и Java та же операция округляет к нулю, и знаки будут другими — это частая ловушка при переносе кода.
Знаковые и беззнаковые целые
Целые бывают знаковыми (signed) и беззнаковыми (unsigned). Знаковый тип отводит один бит под знак и хранит и отрицательные, и положительные значения. Беззнаковый хранит только неотрицательные, зато его верхняя граница вдвое больше при той же ширине.
Беззнаковые типы есть в C, C++ и C#, но их нет как отдельных типов в Java: там все целые знаковые (исключение — 16-битный char, он беззнаковый). С Java 8 появились статические методы для беззнаковой интерпретации (например, Integer.toUnsignedLong), но отдельного типа unsigned int в языке по-прежнему нет.
Беззнаковые целые удобны для битовых масок и счетчиков, но требуют осторожности: вычитание большего из меньшего не даст отрицательного результата, а завернется к огромному положительному числу.
Переполнение int
Переполнение — это ситуация, когда результат операции выходит за границы диапазона типа. Поведение зависит от языка, и это одно из главных отличий целых типов на практике.
В беззнаковых типах C и C++ переполнение определено стандартом: значение заворачивается по модулю (для 8 бит — по модулю 256). Для знаковых типов в C и C++ переполнение — это неопределенное поведение (undefined behavior), результат не гарантирован. В Java и C# знаковое переполнение определено и заворачивается по правилам дополнительного кода. В Python переполнения нет вовсе. Посмотрим на заворот в C:
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("sizeof: char=%zu short=%zu int=%zu long=%zu long long=%zu\n",
sizeof(char), sizeof(short), sizeof(int), sizeof(long), sizeof(long long));
printf("int: %d .. %d\n", INT_MIN, INT_MAX);
printf("uint: 0 .. %u\n", UINT_MAX);
unsigned char uc = 255;
uc = uc + 1; /* беззнаковое переполнение: заворот по модулю 256 */
printf("255 + 1 в unsigned char = %u\n", uc);
unsigned int b = (unsigned int)INT_MAX + 1U; /* считаем в unsigned - определено */
printf("INT_MAX + 1 в unsigned = %u\n", b);
return 0;
}
Вывод программы (собрано и запущено на 64-битной macOS):
sizeof: char=1 short=2 int=4 long=8 long long=8
int: -2147483648 .. 2147483647
uint: 0 .. 4294967295
255 + 1 в unsigned char = 0
INT_MAX + 1 в unsigned = 2147483648
Прибавление единицы к 255 в unsigned char дало 0 — значение завернулось. Именно так работают счетчики, которые обнуляются при переполнении. Обратите внимание: sizeof выдал long равным 8 байтам, потому что программа собрана на macOS; на Windows тот же тип занял бы 4 байта.
Операции над int
Над целыми доступны три группы операций. Знать их набор важнее, чем заучивать синтаксис отдельного языка.
- Арифметические: сложение (+), вычитание (-), умножение (*), целочисленное деление и остаток (в Python — // и %, в C и Java — / и % для целых). Инкремент (++) и декремент (—) есть в C, C++, Java и C#, но не в Python.
- Сравнения: равно (==), не равно (!=), больше (>), меньше (<), больше или равно (>=), меньше или равно (<=). Результат — логическое значение.
- Побитовые: и (&), или (|), исключающее или (^), инверсия (~), сдвиги влево (<<) и вправо (>>). Они работают с двоичным представлением числа и обычно быстрее арифметики.
Здесь стоит развести частую путаницу: оператор ^ во всех перечисленных языках — это побитовое исключающее или (XOR), а не возведение в степень. Возведение в степень в Python записывается как **, а в C, C++ и Java отдельного оператора нет — используют функцию pow из стандартной библиотеки.
Выводы
- Тип данных задает значению две вещи: диапазон допустимых значений и разрешенные операции; целые числа — примитивный тип.
- Разрядность int определяет диапазон: n бит со знаком дают от минус 2^(n-1) до 2^(n-1) минус 1; ширина int зависит от языка и платформы.
- Беззнаковые целые есть в C, C++, C#, но не в Java; в Python целые не имеют фиксированной границы и не переполняются.
- Переполнение ведет себя по-разному: заворот в беззнаковых типах C и в Java, неопределенное поведение для знаковых в C и C++, отсутствие переполнения в Python.
Где применяется и что учить дальше
Целые числа — основа почти любой программы: счетчики циклов, индексы массивов, идентификаторы записей в базе, коды состояния, битовые флаги. Понимание разрядности и переполнения нужно везде, где важны производительность и корректность, — от финансовых расчетов до работы с сетевыми протоколами и хешами.
Освойте тему на практике
Начинать удобнее с языка, где не нужно вручную следить за разрядностью и переполнением. В Python целые ведут себя предсказуемо, и на них проще разобрать сами операции, а разрядность и знаковость освоить уже осознанно. Системно пройти путь от переменных и типов до практических задач помогает курс Python Basic. Оценить формат и уровень до старта можно на бесплатных открытых уроках Otus — это живые занятия с преподавателями.
Смежные темы: Типы данных в языках программирования, Типизация в программировании, Структуры и типы данных.
FAQ
Чем int отличается от float? int хранит целые числа точно, без дробной части. float и double хранят числа с плавающей запятой и приблизительно — у них ограничена точность, поэтому для денег и счетчиков берут целые, а не дробные типы.
Что выбрать — int или long? Если значение гарантированно помещается в 32 бита (примерно до двух миллиардов), достаточно int. Для больших величин — количества байт в большом файле, времени в миллисекундах — берут 64-битный тип (long в Java, long long или int64_t в C/C++).
Почему в C рекомендуют int32_t вместо int? Потому что ширина int зависит от платформы, а int32_t из stdint.h гарантирует ровно 32 бита. Это делает поведение кода предсказуемым при переносе между системами и компиляторами.



