unsigned int
Тип unsigned int хранит только неотрицательные целые числа: на AVR-платах это 2 байта (0–65 535), на Arduino Due — 4 байта (0–4 294 967 295).
Полная статья
Описание
Тип unsigned int — это беззнаковое целое число. В отличие от обычного int, он не резервирует старший бит под знак, поэтому весь диапазон значений уходит в положительную сторону.
На платах UNO и других платах на базе ATMEGA unsigned int занимает 2 байта и хранит значения от 0 до 65 535 (2¹⁶ − 1).
На Arduino Due тип unsigned int занимает 4 байта и охватывает диапазон от 0 до 4 294 967 295 (2³² − 1).
В чём принципиальное отличие от int? В знаковом int старший (15-й) бит интерпретируется как знак числа: если он равен 1, число считается отрицательным, а остальные 15 бит кодируют его величину в Дополнительная математика до 2. В unsigned int такой интерпретации нет — все 16 бит кодируют само значение.
Синтаксис
unsigned int var = val;
Параметры
var: имя переменнойval: начальное значение, которое присваивается переменной
Пример кода
unsigned int ledPin = 13;
Примечания и предупреждения
Переполнение (wrap-around)
Когда значение unsigned int выходит за пределы допустимого диапазона, оно «оборачивается»: превышение максимума возвращает переменную к нулю, а уход ниже нуля перебрасывает её к максимуму:
unsigned int x;
x = 0;
x = x - 1; // x теперь содержит 65535 — переполнение в отрицательную сторону
x = x + 1; // x теперь содержит 0 — переполнение
Это поведение предсказуемо и иногда используется намеренно — например, в счётчиках, которые должны циклически возвращаться к нулю.
Неожиданные результаты в арифметике
Даже если ваша unsigned int-переменная никогда не выходит за границы, смешанная арифметика может дать неожиданный результат. Микроконтроллер руководствуется двумя правилами:
- Тип целевой переменной определяет тип операции. Если результат записывается в знаковую переменную, вся операция выполняется как знаковая — даже если оба операнда беззнаковые.
- Тип промежуточного результата определяется типами операндов. Если оба операнда беззнаковые, промежуточный результат тоже будет беззнаковым — независимо от того, куда он в итоге запишется. Это источник классических ошибок: выражение вычисляется «не в том типе» ещё до присваивания.
unsigned int x = 5;
unsigned int y = 10;
int result;
result = x - y; // 5 - 10 = -5, как и ожидалось
result = (x - y) / 2; // 5 - 10 в беззнаковой арифметике равно 65530! 65530/2 = 32765
// решение: используйте знаковые переменные или выполняйте вычисление пошагово.
result = x - y; // 5 - 10 = -5, как и ожидалось
result = result / 2; // -5/2 = -2 (только целочисленная арифметика, дробная часть отбрасывается)
Когда использовать unsigned int?
- Когда нужно поведение с переполнением — например, счётчики событий, которые должны обнуляться после максимума.
- Когда диапазона знакового
int(до 32 767) не хватает, но вы хотите избежать затрат памяти и скорости, которые несут типыlongилиfloat. - Когда вы работаете с данными, которые по природе своей неотрицательны: размеры, адреса, количества.
Практические замечания
- Не смешивайте без необходимости знаковые и беззнаковые типы в одном выражении — компилятор может вести себя не так, как вы ожидаете, и предупреждения (
-Wsign-compare) помогут это обнаружить. - Если вы вычитаете два значения типа
unsigned intи результат теоретически может оказаться отрицательным, вы получите огромное положительное число вместо отрицательного — это частая причина ошибок в условиях. - Размер
unsigned intзависит от платы: на AVR это 2 байта, на Due — 4. Если нужна переносимость, используйте типы с явным размером из заголовка<stdint.h>:uint16_tилиuint32_t. - Функция
millis()возвращаетunsigned long— неunsigned int. Не путайте эти типы при работе со временем. - Для отладки выводите значения через
Serial.println(): так вы сразу увидите, произошло ли переполнение.