преобразование -1 в беззнаковые типы - PullRequest
9 голосов
/ 21 ноября 2011

Рассмотрим следующий код для установки всех битов x

unsigned int x = -1;

Это портативное устройство?Кажется, работает как минимум на Visual Studio 2005-2010

Ответы [ 4 ]

6 голосов
/ 21 ноября 2011

Цитируемый ответ:

Я знаю, что здесь есть много правильных ответов, но я хотел бы добавить несколько цитат к смеси. Я приведу два стандарта: черновик C99 n1256 (в свободном доступе) и черновик C ++ n1905 (также в свободном доступе). В этих конкретных стандартах нет ничего особенного, они просто доступны бесплатно, и то, что оказалось проще всего найти в настоящий момент.

Версия C ++:

§5.3.2 ¶9: Согласно этому параграфу, значение ~(type)0 гарантированно установит все биты, если (type) - тип без знака.

Операнд ~ должен иметь целочисленный тип или тип перечисления; результат - дополнение его операнда. Интегральные акции выполняются. Тип результата - это тип повышенного операнда.

§3.9.1 ¶4: это объясняет, как переполнение работает с числами без знака.

Целые числа без знака, объявленные как без знака, должны подчиняться законам арифметики по модулю 2 n , где n - количество бит в представлении значения этого конкретного размера целого числа.

§3.9.1 ¶7, плюс сноска 49: Это объясняет, что числа должны быть двоичными. Отсюда можно сделать вывод, что ~(type)0 должно быть наибольшим представимым числом в type (поскольку в нем включены все биты и каждый бит аддитивен).

Представления целочисленных типов должны определять значения с использованием чистого двоичная система счисления 49 .

49) Позиционное представление для целых чисел, использующее двоичные цифры 0 и 1, в котором значения, представленные последовательными битами, являются аддитивными, начинаются с 1, и умножаются на последовательную интегральную степень 2, за исключением, возможно, бита с самой высокой позицией. (Адаптировано из American National Словарь по системам обработки информации .)

Поскольку арифметика выполняется по модулю 2 n , гарантируется, что (type)-1 является наибольшим значением, представимым в этом типе. Также гарантируется, что ~(type)0 является наибольшим значением, представимым в этом типе. Поэтому они должны быть равны.

Версия C99:

В версии C99 это изложено гораздо более компактно и явно.

§6.5.3 ¶3:

Результатом оператора ~ является побитовое дополнение его (повышенного) операнда (то есть каждый бит в результате устанавливается тогда и только тогда, когда соответствующий бит в преобразованном операнде равен не установлен). Целочисленные продвижения выполняются на операнде, и результат имеет повышенный тип. Если повышенный тип является беззнаковым типом, выражение ~ E эквивалентно до максимального значения, представимого в этом типе минус E.

Как и в C ++, арифметика без знака гарантированно является модульной (я думаю, что я уже достаточно подробно изучил стандарты), поэтому стандарт C99 определенно гарантирует, что ~(type)0 == (type)-1, и мы знаем из §6.5.3 №3 что в ~(type)0 должны быть установлены все биты.

Краткое содержание:

Да, это портативный. unsigned type x = -1; гарантирует, что все биты установлены в соответствии со стандартом.

Сноска: Да, мы говорим о битах значения , а не битах заполнения . Однако я сомневаюсь, что вам нужно установить биты заполнения на один. Из недавнего вопроса переполнения стека ( link ) видно, что GCC был портирован на PDP-10, где тип long long имеет один бит заполнения. В такой системе unsigned long long x = -1; может не устанавливать этот бит заполнения равным 1. Однако вы сможете обнаружить это только при использовании приведения указателей, который в любом случае обычно не переносим.

6 голосов
/ 21 ноября 2011

Видимо, это:

(4.7) Если тип назначения не имеет знака, полученное значение будет наименьшим целое число без знака, совпадающее с целым числом источника (по модулю 2 n , где n - количество битов, используемых для представления типа без знака). [Примечание: в Представление дополнения двух, это преобразование является концептуальным и в битовой комбинации нет изменений (если нет усечения).

Гарантируется, что это будет наибольшее возможное количество для этого типа благодаря свойствам по модулю.

C99 также позволяет:

В противном случае, если новый тип является беззнаковым, значение преобразуется путем многократного добавления или вычитания на единицу больше максимального значения, которое может быть представлен в новом типе, пока значение не находится в диапазоне новый тип. 49)

Какая сумма будет также наибольшей из возможных.


Максимально возможное количество может быть не для всех установленных битов. Для этого используйте ~static_cast<unsigned int>(0).

5 голосов
/ 21 ноября 2011

Я неаккуратно читал вопрос и сделал несколько комментариев, которые могут ввести в заблуждение из-за этого. Я постараюсь прояснить путаницу в этом ответе.

Декларация

unsigned int x = -1;

гарантированно устанавливает x в UINT_MAX, максимальное значение типа unsigned int. Выражение -1 имеет тип int и неявно преобразуется в unsigned int. Преобразование (которое определяется в терминах значений, а не представлений) приводит к максимальному значению целевого типа без знака.

(бывает, что семантика преобразования оптимизирована для систем с двумя дополнительными компонентами; для других схем преобразование может включать нечто большее, чем просто копирование битов.)

Но вопрос касался установки всех битов x. Итак, UINT_MAX представлен как все-бит-один?

Существует несколько возможных представлений для целых чисел со знаком (наиболее часто встречаются дополнения до двух, но также возможны дополнения и значения со знаком). Но мы имеем дело с целым типом без знака , поэтому способ представления целых чисел со знаком не имеет значения.

Целые числа без знака должны быть представлены в чистом двоичном формате. Предполагая, что все биты представления вносят вклад в значение объекта unsigned int, тогда да, UINT_MAX должен быть представлен как all-bits-one.

С другой стороны, целочисленные типы могут иметь биты заполнения , биты, которые не способствуют представлению. Например, допустимо, чтобы unsigned int было 32 бита, но только 24 из этих битов должны быть битами значения, поэтому UINT_MAX будет равно 2 * 24-1, а не 2 * 32-1 , Так что в самом общем случае все, что вы можете сказать, это то, что

unsigned int x = -1;

устанавливает все значения битов x в 1.

На практике очень немногие системы имеют биты заполнения в целочисленных типах. Таким образом, в подавляющем большинстве систем unsigned int имеет размер N битов и максимальное значение 2 ** N-1, а приведенное выше объявление будет устанавливать все биты x в 1.

Это:

unsigned int x = ~0U;

также установит для x значение UINT_MAX, поскольку побитовое дополнение для типов без знака определяется в терминах вычитания.

2 голосов
/ 21 ноября 2011

Осторожно!

Это определяется реализацией, как то, как должно быть представлено отрицательное целое число, дополнение к двум или что, не определено Стандартом C ++.Это зависит от компилятора, который принимает решение и должен правильно его документировать.

Короче говоря, он не переносим.Он не может установить все биты x .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...