Что делает унарный оператор "-", делают на неподписанных типах данных в C/C++ (и на различных компиляторах)?

Например:

unsigned int numA = 66;//or anything really
unsigned int numB = -numA;
unsigned int numC = numA & numB

Я понимаю, что оператор побитового дополнения может использоваться, чтобы получить дополнение two (вместе с +1).

Причина, которую я спрашиваю, состоит в том, потому что я наткнулся на это в некотором коде для шахматного двигателя. Шахматные двигатели делают много 'hacky' вещей получить абсолютную скорость, особенно в функциях поколения движения, которые вызваны миллионы времен в секунду. (Не помогает, что это был пример волшебства bitboard поколение движения - наиболее оптимизированный из них всех). Этот шахматный код двигателя в особенности только работает правильно при gcc компиляции (я подозреваю).

Как различные компиляторы рассматривают это? В частности, как делает ручку gcc это по сравнению с компилятором C++ в ПРОТИВ Экспресса Студии 2012 года.

Спасибо.

6
добавлено отредактировано
Просмотры: 1
nl ja de

4 ответы

Соответствующая цитата из Стандарта - на самом деле это:

(§5.3.1/8) Операнд одноместного - у оператора должен быть арифметический или нерассмотренный тип перечисления, и результат - отрицание своего операнда. Составное продвижение выполняется на операндах перечисления или интеграле. Отрицание неподписанного количества вычисляется, вычитая его стоимость от 2 <�глоток> n </глоток>, где n - число битов в продвинутом операнде. Тип результата - тип продвинутого операнда.

(Это от C++ 11; это раньше было 5.3.1/7 в более старых версиях.)

So -num will be evaluated as 2CHAR_BIT*sizeof(num) - num (&ddagger;). The result will be of the same type as the operand (after integer promotion), i.e. it will also be unsigned.

Я просто проверил с GCC, и это, кажется, выполняет операцию точно способом, описанным Стандартом. Я приму дело обстоит так для Visual C++ также; иначе это - ошибка.


(&ddagger;) This formula assumes that the relevant number of bits corresponds to the size (in bits) of the variable in memory. As Keith Thompson points out in the comment, this can't be true if there are padding bits (i.e. when not all bits participate in the representation of the numerical value, which is possible according to §3.9.1/1). On a system that uses more bits to store the value than are used to represent the numerical value, the formula will not be accurate. (I, personally, am not actually aware of any such system, though.)

12
добавлено
@KeithThompson Да, я на самом деле задался вопросом об этом. В Стандарте явно говорится в 3.9.1/1, что в целых типах кроме случайная работа , не все биты обязательно участвуют в представлении значения. Но в разделе, указанном выше, это говорит n </ код> является числом битов (не число битов, которые участвуют в представлении значения). Очевидно, дополняя биты can' t возможно учитываются (иначе это doesn' t имеют смысл), но формулировка в Стандарте isn' t довольно точный здесь.
добавлено автор jogojapan, источник
"Число битов" doesn' t включают любые биты дополнения (которых нет ни одного в большинстве внедрений), таким образом, выражение, включающее, CHAR_BIT (который я can' t воспроизводят в комментарии), isn' t всегда точный.
добавлено автор Keith Thompson, источник

Вот то, что стандарт C++ говорит согласно разделу 4.7.2 (Составные преобразования):

Если тип назначения не подписан, получающаяся стоимость - наименьшее количество целое без знака, подходящее исходному целому числу (модуль 2 <�глоток> n </глоток>, где n число битов, используемых, чтобы представлять неподписанный тип). [Отметьте: В дополнительное представление two, это преобразование концептуально и нет никакого изменения в комбинации двоичных разрядов (если нет никакого усечения). — закончите примечание]

Надежда это отвечает на ваш вопрос.

3
добавлено
Это doesn' t непосредственно отвечают на вопрос. В OP' нет никакого преобразования; s пример кода (другой преобразование 66 из интервал , чтобы неподписанный интервал ). Одноместное "-" применяется к , неподписанный стоимость, и уступает , неподписанный результат. (Это действительно объясняет значение неподписанный интервал макс. =-1; , но это wasn' t вопрос.)
добавлено автор Keith Thompson, источник

Вы спросили и о C и о C++. Помните, что они - два различных языка. В данном случае у них есть те же самые правила для операций на неподписанных типах, но они выражаются по-другому.

Цитирование последний проект из тока (2011) стандарт ISO C), раздел 6.2.5p9:

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

Описание одноместного "-" оператор просто говорит, что результат - "отрицание своего (продвинутого) операнда"; это предполагает, что читатель читал 6.2.5, чтобы выяснить, каково "отрицание" целого без знака.

На любом языке, результате:

unsigned int numA = 66;
unsigned int numB = -numA;

должен сохранить UINT_MAX - 66U + 1U в , оцепенелом . (<�Код> U суффиксы не действительно необходимы, но я включаю их, чтобы подчеркнуть, что это все определяется с точки зрения неподписанных ценностей.)

2
добавлено

Я был укушен typeof (-Неподписанный), Не подписано. Компилятор VS2012 берет это к интересным уровням непостижимого поведения:

неподписанный x = 0xFFFFFFFE; интервал y =-x/2;

Что такое "y"?

Я ожидал бы x/2 = 0x7FFFFFFF, тогда - (x/2) = 0x80000001, т.е.-2 ** 31-1. Вместо этого компилятор производит (-x) = 0x00000002, (-x)/2 = 0x00000001.

Я предполагаю, что для граничных значений, это - весь Deathstar 9000. Вздох.

0
добавлено
Проверьте, что у стола предшествования, одноместного - , есть более высокое предшествование, чем /
добавлено автор M.M, источник
Спасибо. И слишком поздно, я сделал. Реальное удивление, конечно, состояло в том, что "-(неподписанный)" имеет неподписанный тип.
добавлено автор Mischa, источник