Ответ 1
ISO C (C99 section 6.2.6.2/2
в этом случае, но он переносит на более поздние итерации стандарта (a)), заявляет, что реализация должна выбрать одно из трех разных представлений для целочисленных типов данных, два дополнения, одно дополнение или знак/величина (хотя невероятно вероятно, что две реализации дополнения намного перевешивают другие).
Во всех этих представлениях положительные числа идентичны, единственная разница заключается в отрицательных числах.
Чтобы получить отрицательное представление для положительного числа, вы:
- инвертировать все биты, а затем добавить один на два дополнения.
- инвертировать все биты для дополнения.
- инвертировать только бит знака для знака/величины.
Вы можете увидеть это в таблице ниже:
number | two 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-разрядный со знаком int, есть бит заполнения (в середине 32-битного), который игнорируется при определении значения 32-разрядного со знаком int. Но если этот 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).