Перейти к содержанию

Флаг переполнения (V)

Флаг переполнения V процессор устанавливает, когда сумма или разность чисел со знаком не поместилась в разрядность и сменила знак: два положительных числа дали отрицательное или наоборот. Для беззнаковых чисел этот флаг ничего не значит — для них есть флаг переноса.

Обновлено Редакция GAW

Флаг переполнения (overflow flag, V) — бит регистра состояния, который устанавливается, когда результат сложения или вычитания чисел со знаком в дополнительном коде не помещается в разрядность. Признак простой: при сложении оба операнда одного знака, а результат — противоположного. Для 8 бит у AVR (команда ADD) это записано так:

V=a7 b7 r7‾+a7‾ b7‾ r7,V = a_7 \, b_7 \, \overline{r_7} + \overline{a_7} \, \overline{b_7} \, r_7,

где a7, b7 — знаковые биты слагаемых, r7 — знаковый бит результата. У AVR это бит V регистра SREG (Two's Complement Overflow Flag), у Cortex-M — бит V регистра APSR.

Перенос и переполнение

Операция (8 бит)РезультатCVСмысл
0x7F + 0x010x8001127 + 1: без знака 128 — верно, со знаком −128 — переполнение
0xFF + 0x010x0010без знака 256 не влезло; со знаком −1 + 1 = 0 — верно
0x80 + 0x800x0011−128 + −128: переполнение в обоих смыслах

Значения флагов получены по формулам руководства AVR. Одно и то же сложение обслуживает оба типа чисел, а программа выбирает нужный флаг: флаг переноса C для беззнаковых, V — для знаковых.

Где используется

  • Знаковое сравнение. AVR вычисляет S = N ⊕ V и переходит по BRGE/BRLT; Cortex-M — по условиям GE (N = V) и LT (N ≠ V). Без учёта V сравнение −100 с 100 дало бы неверный ответ.
  • Отрицание. Команда NEG у AVR устанавливает V для 0x80: −(−128) в 8 битах не представимо и остаётся 0x80.
  • Арифметика с насыщением в цифровой обработке сигналов и формате Q: по переполнению результат заменяют наибольшим или наименьшим значением вместо «заворачивания».

Не все команды трогают V: у Cortex-M умножение MUL его не меняет, а деление SDIV для 0x80000000 / −1 возвращает 0x80000000 без всякого признака. В языке C знаковое переполнение — неопределённое поведение (C11, 6.5p5), поэтому полагаться на флаг из программы на C нельзя. Флаги N, Z, C, V для сложения, вычитания и сдвигов AVR и Cortex-M показывает калькулятор двоичной арифметики.

Частые вопросы

Когда устанавливается флаг переполнения?

При сложении — если оба слагаемых одного знака, а результат другого: 0x7F + 0x01 = 0x80, то есть +127 + 1 дало −128. При вычитании — если знаки операндов разные и знак результата не совпал со знаком уменьшаемого. Сложение чисел разных знаков переполниться не может.

Зачем у AVR ещё и флаг S?

S = N ⊕ V — истинный знак результата с учётом переполнения. После сравнения −100 и 100 разность −200 не помещается в 8 бит и выглядит положительной (N = 0), но V = 1, и S = 1 правильно говорит «меньше». Команды BRGE и BRLT смотрят именно на S, у Cortex-M условия GE и LT — на равенство N и V.

Можно ли в C проверить переполнение по флагу V?

Нет: знаковое переполнение в C — неопределённое поведение, и компилятор вправе считать, что его не бывает. Проверяют заранее, по диапазонам операндов, или считают в беззнаковом или более широком типе: беззнаковая арифметика в C определена и просто «заворачивается» по модулю 2ⁿ.

Источники

  1. Microchip. AVR Instruction Set Manual, DS40002198B, 2021 — V — Two's Complement Overflow Flag; 6.2 ADD: V = Rd7·Rr7·¬R7 + ¬Rd7·¬Rr7·R7, S = N ⊕ V; 6.119 SUB: V = Rd7·¬Rr7·¬R7 + ¬Rd7·Rr7·R7; 6.80 NEG: V = 1 при результате 0x80; 6.15/6.21 BRGE, BRLT по флагу S
  2. Arm. Armv7-M Architecture Reference Manual, ARM DDI 0403E.e — A2.2.1 AddWithCarry(): флаг V — знаковое переполнение; A7.3, табл. A7-1: GE — N = V, LT — N ≠ V; A7.7.84 MUL не меняет V; A7.7.127 SDIV: 0x80000000 / −1 даёт 0x80000000 без признака переполнения
  3. ISO/IEC 9899:201x (C11), Committee Draft N1570, 2011 — 6.5p5: результат вне диапазона типа — неопределённое поведение; 6.3.1.3p3: преобразование в знаковый тип, не вмещающий значение, — определяется реализацией

Нашли ошибку?