Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

Способ представления знаковых целых в C++

#c++ #language_lawyer


В стандарте языка указано, что для для представления целочисленных типов (integral
types) допускается использовать один из трёх способов: 


2's complement, 
1's complement, 
signed magnitude. 


В связи с чем возникает несколько вопросов:


В настоящее время где-нибудь вообще используется представление целых чисел, отличное
от 2's complement?
Допускает ли стандарт, чтобы в рамках одной и той же реализации использовались различные
представления для целочисленных типов? Например, чтобы char был 2's complement, а int
был 1's complement?
Как различные представления целых согласуются с битовыми операциями? Например, пусть
есть такой код:

unsigned char a = 1;    
a = ~a;



И пусть в некоторой реализации используется восьмибитный char и шестнадцатибитный
int, и для представления целых знаковых чисел применяется 1's complement, т.е. отрицательные
значения мы храним в обратном коде. У меня сложилось впечатление, что для вычисления
значения переменной a могут быть проделаны следующие преобразования:


Переменная a подвергнется целочисленному расширению до int, ибо операнд битового
отрицания, согласно стандарту, может быть расширен. Т.е. набор битов 00000001 преобразуется
в 00000000 00000001.
Произойдёт инвертирование битов, т.е. расширенное значение примет вид 11111111 11111110.
Данная последовательность бит будет интерпретироваться как знаковое целое, ибо, согласно
стандарту, результат битового отрицания имеет тип расширенного операнда. Данная последовательность
бит в обратном коде означает целое число -1.
Целое число -1 будет приведено к беззнаковому целому unsigned char по модулю 256.
Т.е. переменная a примет значение 255, которое кодируется следующей последовательностью
бит: 11111111. Что несколько странно, ибо используя битовое отрицание к последовательности
бит 00000001, я ожидаю получить 11111110, а не 11111111.  


Допускается ли стандартом такая работа битового отрицания, или приведённый выше пример
в корне не верен?
    


Ответы

Ответ 1



Говорят, что системы типа UNISYS 2200 (1, 2) еще встречаются кое-где в реальной жизни. Штатный компилятор С в этих системах использует 1's-complement представление. См. также Are there any non-twos-complement implementations of C? Exotic architectures the standards committees care about Прямого запрета на смешение представлений в стандарте нет. Да и нет в таком запрете никакого смысла, ибо никакой пользы он бы не принес - стандарт и так не гарантирует вам никакой "синхронизированности" между представлениями разных знаковых целых типов. Например, каждый целый тип может обладать своим количеством и расположением padding-битов. Ваша интерпретация работы оператора ~ совершенно верна. Да, такое поведение допускается. Да, поведение "малых" беззнаковых типов в таких контекстах существенно зависит от выбранного представления знаковых типов. Точнее, побитовое поведение знаковых типов очевидным образом зависит от выбранного представления, а "малые" беззнаковые типы уже становятся заложниками этого поведения через посредство integral promotions. Можно также отметить, что применение ~ к знаковому значению может породить и trap representation. (Свою роль тут также сыграл сделанный на этапе формирования C89/90 выбор в пользу выполнения расширения беззнаковых типов к знаковому int, как описано в Rationale к стандарту (см. вторую часть моего ответа здесь), вопреки имевшей место тогда юниксовой традиции расширения беззнаковых типов к unsigned int.)

Комментариев нет:

Отправить комментарий