ISO C (C99 section 6.2.6.2/2
в данном случае, но он переносит на более поздние итерации стандарта (a) ), в котором указывается, что реализация должна выбрать одно из трех различных представлений для целочисленных типов данных, дополнение к двум , дополнение или знак / величина (хотя невероятно вероятно, что реализации дополнения двух намного перевешивают другие).
Во всех этих представлениях положительные числа идентичны, единственной разницей являются отрицательные числа.
Чтобы получить отрицательное представление для положительного числа, вы:
- инвертировать все биты, затем добавить один для дополнения до двух.
- инвертировать все биты для дополнения.
- инвертировать только бит знака для знака / величины.
Вы можете увидеть это в таблице ниже:
number | two's complement | ones' complement | sign/magnitude
=======|=====================|=====================|====================
5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101
-5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101
Имейте в виду, что ISO не требует, чтобы все биты использовались в представлении. Они вводят концепцию знакового бита, битов значения и битов заполнения. Теперь я на самом деле не видел реализацию с битами заполнения, но из документа обоснования C99 у них есть это объяснение:
Предположим, что машина использует пару 16-битных шорт (каждая со своим собственным знаковым битом) для создания 32-битного целого числа, а знаковый бит нижнего короткого замыкания игнорируется при использовании в этом 32-битном целом. Затем, как 32-разрядное знаковое целое, существует бит дополнения (в середине 32-разрядного), который игнорируется при определении значения 32-разрядного знакового целого. Но если этот 32-битный элемент обрабатывается как 32-битное беззнаковое целое, то этот бит дополнения виден программе пользователя. Комитету C было сказано, что есть машина, которая работает таким образом, и это одна из причин, по которой биты заполнения были добавлены в C99.
Я полагаю, что машина, о которой они, возможно, имели в виду, была Datacraft 6024 (и это наследники из Harris Corp). В этих машинах у вас было 24-битное слово, используемое для целого числа со знаком, но, если вы хотели получить более широкий тип, два из них были объединены в 47-битное значение, а знаковый бит одного из слов игнорировался:
+---------+-----------+--------+-----------+
| sign(1) | value(23) | pad(1) | value(23) |
+---------+-----------+--------+-----------+
\____________________/ \___________________/
upper word lower word
(a) Интересно, что с учетом нехватки современных реализаций, которые на самом деле используют два других метода, был толчок к принятию дополнения до двух в качестве одного истинного метода. Это прошло довольно длинный путь в стандарте C ++ (WG21 - рабочая группа, ответственная за это) и теперь, очевидно, рассматривается и для C (WG14).