В чем разница между прямым присвоением результата операции левого сдвига переменной и операции присваивания левого сдвига в C?
В следующем выражении результат операции сдвига влево присваивается переменной i
.
int i;
i = 7 << 32;
printf("i = %d\n",i);
В следующем выражении операция присваивания левого сдвига переносится.
int x = 7;
x <<= 32;
printf("x = %d\n",x);
Оба приведенных выше выражения дали разные результаты. Но это не то же самое со следующими двумя выражениями. Оба они дали тот же результат. Итак, что может быть причиной того, что приведенные выше выражения возвращают разные значения?
int a;
a = 1 + 1;
printf("a = %d\n",a);
int b = 1;
b += 1;
printf("b = %d\n",b);
Ответы
Ответ 1
В стандарте C говорится:
Результат undefined, если правый операнд отрицательный или больше чем или равно количеству бит в типе левых выражений.
Итак, это undefined поведение, потому что int
обычно имеет размер 32
, что означает, что только 0
через 31
шаги четко определены.
Ответ 2
Я согласен с комментариями Коди Грея. Просто для людей в будущем, которые здесь заканчиваются, способ разрешить эту двусмысленность - использовать unsigned long long.
unsigned long long int b = 7ULL<<32; // ULL here is important, as it tells the compiler that the number being shifted is more than 32bit.
unsigned long long int a = 7;
a <<=32;
Ответ 3
Абстрактная оперативная семантика из ISO/IEC 9899
гласит:
6.5.7 Bitwise shift operators --- Semantics
3........ Если значение правильного операнда отрицательный или больше или равен ширина продвинутого левого операнда, поведение undefined.
В вашем случае, разобрав и увидев, что происходит, мы видим так:
[[email protected] stub]# objdump -d a.out | sed '/ <main>/,/^$/ !d'
00000000004004f6 <main>:
4004f6: 55 push %rbp
4004f7: 48 89 e5 mov %rsp,%rbp
4004fa: 48 83 ec 10 sub $0x10,%rsp
4004fe: c7 45 fc 07 00 00 00 movl $0x7,-0x4(%rbp)
400505: b8 20 00 00 00 mov $0x20,%eax
40050a: 89 c1 mov %eax,%ecx
40050c: d3 65 fc shll %cl,-0x4(%rbp) <<== HERE IS THE PROBLEM
40050f: 8b 45 fc mov -0x4(%rbp),%eax
400512: 89 c6 mov %eax,%esi
400514: bf b4 05 40 00 mov $0x4005b4,%edi
400519: b8 00 00 00 00 mov $0x0,%eax
40051e: e8 cd fe ff ff callq 4003f0 <[email protected]>
400523: b8 00 00 00 00 mov $0x0,%eax
400528: c9 leaveq
400529: c3 retq
40052a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
Сгенерированный код действительно сдвигается, но shll %cl,-0x4(%rbp)
(сдвиг влево от длинного) не имеет эффекта.
undefined behaviour
в этом случае заключается в сборке, а именно в операции SHL.