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

Флаг переноса (C)

Когда сумма двух 8-битных чисел не помещается в 8 бит, девятый бит процессор не теряет, а кладёт во флаг переноса C. По этому флагу складывают длинные числа частями и сравнивают беззнаковые значения.

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

Флаг переноса (carry flag, C) — бит регистра состояния процессора, в который арифметические команды записывают перенос из старшего разряда результата. Для сложения n-битных чисел без знака C = 1 означает, что настоящая сумма не меньше 2n и в регистре остался только её остаток:

a+b=R+C⋅2n,0≤R<2n.a + b = R + C \cdot 2^n, \qquad 0 \le R < 2^n.

У AVR это бит C регистра SREG (Carry Flag), у Cortex-M — бит C регистра APSR.

Что делает флаг

  • Длинная арифметика. Числа шире регистра складывают частями: младшие байты обычной командой, старшие — с учётом переноса. Пример из руководства AVR: add r2, r0 и затем adc r3, r1 дают 16-битную сумму. Вычитание так же: sub и sbc.
  • Заём при вычитании. У AVR (команда SUB) C устанавливается, если вычитаемое по модулю больше уменьшаемого, то есть был заём. У ARM наоборот: вычитание выполняется как сложение с инверсией, и C = 1 означает «заёма не было» — руководство Armv7-M называет его флагом «не заём».
  • Сравнение без знака. Команда сравнения — это вычитание без записи результата. AVR после CP переходит по BRLO (C = 1, меньше) и BRSH (C = 0, больше или равно), Cortex-M — по условиям LO/CC и HS/CS.
  • Сдвиги. LSL и LSR у AVR кладут в C выдвинутый бит, так сдвигают многобайтные числа.

Пример

0xFF + 0x01 в 8 битах: в регистре 0x00, C = 1, а флаг переполнения V = 0 — для знаковых чисел это −1 + 1 = 0, верный результат. Значит, по одному и тому же сложению беззнаковый код смотрит на C, а знаковый — на V; само сложение одинаково благодаря дополнительному коду.

В языке C флага нет: перенос проверяют сравнением результата с операндом (сумма без знака меньше слагаемого — был перенос), подробнее о типах — в статье «Язык C для микроконтроллеров». Не путать с флагом полупереноса H — переносом из бита 3, нужным для двоично-десятичных чисел. Сложение, вычитание, сдвиги и все флаги AVR и Cortex-M показывает калькулятор двоичной арифметики.

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

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

При сложении — если результат не поместился в разрядность и был перенос из старшего бита: 0xFF + 0x01 в 8 битах даёт 0x00 и C = 1. При вычитании у AVR — если был заём, то есть вычитаемое больше уменьшаемого как беззнаковое. Сдвиги кладут в C выдвинутый бит.

Почему у ARM флаг C при вычитании инвертирован?

ARM вычитает как сложение с инверсией: x − y = x + NOT(y) + 1, и флаг C — это перенос этого сложения. Он равен 1, когда заёма не было (x ≥ y без знака), и 0 при заёме. В руководстве Armv7-M это так и названо — флаг «не заём». У AVR наоборот: C = 1 означает заём.

Отличается ли флаг переноса от флага переполнения?

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

Источники

  1. Microchip. AVR Instruction Set Manual, DS40002198B, 2021 — C — Carry Flag регистра SREG; 6.2 ADD: C — перенос из старшего бита; 6.1 ADC: пример 16-битного сложения add r2,r0 / adc r3,r1; 6.119 SUB: C устанавливается, если вычитаемое по модулю больше уменьшаемого; 6.93 SBC; 6.73/6.74 LSL, LSR — выдвигаемый бит в C; 6.20/6.25 BRLO, BRSH после CP/SUB
  2. Arm. Armv7-M Architecture Reference Manual, ARM DDI 0403E.e — A2.2.1, AddWithCarry(): при вычитании carry_in и carry_out работают как флаги «не заём»; A7.3, табл. A7-1: CS/HS — C = 1 (беззнаковое больше или равно), CC/LO — C = 0, HI — C = 1 и Z = 0

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