Вопрос не вполне по C++, а скорее по железу, но все-таки.
Коллега неожиданно обнаружил. Что напечатает следующая программа?
#include <stdio.h>
int main()
{
unsigned sh = 0x2F;
unsigned v = 1u << sh;
printf("%u", v);
}
Ответ: 32768, что есть "1 << (sh & 31)". Сдвиг на 32 дает единицу.
При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?
Просьба к тем, у кого есть под руками PPC, Sun, HP, SGI и прочие железяки — как там?
Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).
Разумеется, речь идет о платформах с 32-битовыми интами.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Здравствуйте, McSeem2, Вы писали:
MS>При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?
warning C4293: '<<' : shift count negative or too big, undefined behavior
Хотя, как я понял, интересуют именно реальные причины такого поведения. Хз, подождем, что ответят
Здравствуйте, McSeem2, Вы писали:
MS>Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?
(ISO 14882:2003: 5.8/1):
The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.
Из компиляторов которыми я располагаю на платформе x86 все кроме MSVC (/O2) выдали значение 32768.
MS>Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).
(ECMA-334, June 2005: 14.8)
For the predefined operators, the number of bits to shift is computed as follows:
When the type of words, the shift count is computed from count & 0x1F.
When the type of x is long or ulong, the shift count is given by the low-order six bits of count. In other words, the shift count is computed from count & 0x3F.
If the resulting shift count is zero, the shift operators simply return the value of x.
(The Java Language Specification Third Edition: 15.19)
If the promoted type of the left-hand operand is int, only the five lowestorder bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f. The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowestorder bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f. The shift distance actually used is therefore always in the range 0 to 63, inclusive.
Здравствуйте, McSeem2, Вы писали:
MS>Вопрос не вполне по C++, а скорее по железу, но все-таки.
MS>Коллега неожиданно обнаружил. Что напечатает следующая программа? MS>
MS>Ответ: 32768, что есть "1 << (sh & 31)". Сдвиг на 32 дает единицу. MS>При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?
MS>Просьба к тем, у кого есть под руками PPC, Sun, HP, SGI и прочие железяки — как там? MS>Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).
MS>Разумеется, речь идет о платформах с 32-битовыми интами.
0x2f = 47
1u << 47 = 0
А что ты хотел?
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Здравствуйте, McSeem2, Вы писали:
MS>Разумеется, речь идет о платформах с 32-битовыми интами.
Всё просто. На Intel, кажется с 486-го проца есть оптимизация циклических сдвигов.
Типа для операций сдвига используется только младшие пять бит сдвига.
Например на PPC это не так.
Ну а с другой стороны, это всё вполне себе соответсвует стандарту, так как поведение неопределено в таких случаях.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Ubivetz, Вы писали:
U>0x2f = 47 U>1u << 47 = 0 U>А что ты хотел?
В том-то и фишка, что 1<<47 (с константами) дает ноль, а с переменными — 32768:
int sh = 47;
int v = 1 << sh; // 32768
Более того, значение v зависит от опций оптимизатора (сейчас проверил). Если он сумеет вывести константу, будет 0. Если честно сгенерирует инструкции, то 32768.
В общем, куда ни ткни, везде UB (калабур).
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Есть такая особенность у операции сдвига в процессорах x86 — он берет только младшие 5 бит (в общем типа сам накладывает маску 0x1F) от величины сдвига, а потом двигает значение. Я очень долго удивлялся когда сдвигал значения в своем классе эмуляции 64-битного числа. Сдвиг в тесте был на 32 бита — по идее регистр (старшая часть) должен был бы очиститься, а фиг — он вообще не изменился, будто операции и не было.