Расширение знака на литерале против переменной - PullRequest
3 голосов
/ 25 октября 2011

Я работаю с gcc 4.4.5 и испытываю некоторые трудности в понимании оператора сдвига вправо для простых простых значений без знака ...

Этот тест

    ASSERT_EQ( 0u, (unsigned long)(0xffffffff) >> (4*8) );

пройден.

Этот тест

    unsigned long address = 0xffffffff;
    ASSERT_EQ( 0u, address >> (4*8) );

не пройден:

Value of: address >> (4*8)
   Actual: 4294967295
   Expected: 0u

Кажется, что переменная обрабатывается как значение со знаком и, следовательно, приводит к расширению знака.(0xffffffff - это 4294967295 в десятичном виде).Кто-нибудь может заметить разницу?

Ответы [ 4 ]

5 голосов
/ 25 октября 2011

Неопределенное поведение сдвигать значение, большее или равное размеру в битах левого операнда (§5.8¶1). (Я предполагаю, что unsigned long составляет 32 бита из ваших комментариев о том, что 0xfffffff является ожидаемым результатом, если вы рассмотрите расширение знака.)

Тем не менее, вероятно, что ASSERT_EQ делает что-то, что вызывает разницу, поскольку он отлично работает на GCC 4.5 со старым добрым assert.

3 голосов
/ 25 октября 2011

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

2 голосов
/ 25 октября 2011

Если unsigned long - 32 бита, то поведение его сдвига на 32 бита не определено.Цитируя стандарт C ++ 2003:

Поведение не определено, если правый операнд отрицательный или больше или равен длине в битах повышенного левого операнда.

Очевидно, что оценки во время компиляции и во время выполнения выполняются по-разному - что совершенно справедливо, если они дают одинаковые результаты в случаях, когда оно определено.

(Если unsigned long шире, чем 32 битав вашей системе это не относится.)

0 голосов
/ 25 октября 2011

Оба эти теста проходят gcc-4.3.4 со старым assert.

...