Флаг переноса (C)
Когда сумма двух 8-битных чисел не помещается в 8 бит, девятый бит процессор не теряет, а кладёт во флаг переноса C. По этому флагу складывают длинные числа частями и сравнивают беззнаковые значения.
Обновлено Редакция GAW
Флаг переноса (carry flag, C) — бит регистра состояния процессора, в который арифметические команды записывают перенос из старшего разряда результата. Для сложения n-битных чисел без знака C = 1 означает, что настоящая сумма не меньше 2n и в регистре остался только её остаток:
У 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.
Источники
- 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
- 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
Нашли ошибку?
Смотрите также
- Двоичная арифметика и флагиСложение, вычитание, умножение, деление, сдвиги; флаги C, V, N, Z AVR и Cortex-M
- Флаг переполнения (V)Выход знакового результата за диапазон
- Дополнительный кодTwo's complement: запись отрицательных целых
- C для микроконтроллеровТипы, stdint, volatile, атомарность, регистры, константы во Flash
- Арифметический сдвигСдвиг вправо с сохранением знака: деление на 2 со знаком