LINUX.ORG.RU

c/c++ странность с <<

 bitwise left shift, ,


1

0

всю свою сознательную жизнь я думал, что оператор << НЕ ЯВЛЯЕТСЯ ЦИКЛИЧЕСКИМ, но вопрос возник когда в правильно работающей проге нашел логическую ошибку на ровном месте, сам прикол сводится к такому коду:

for (i = 0; i < 64 + 1; i++)
    printf("i = %d; x = 0x%08x\n", i, (0x1 << i));
printf("\nbut i = %d; x = 0x%08x\n", 37, (0x1 << 37));
и выводу
i = 0; x = 0x00000001
i = 1; x = 0x00000002
...
i = 30; x = 0x40000000
i = 31; x = 0x80000000
i = 32; x = 0x00000001 // !!!
i = 33; x = 0x00000002
...
i = 37; x = 0x00000020
...
i = 64; x = 0x00000001 // !!!

but i = 37; x = 0x00000000
причем, это проявляется как на gcc-4.7.2, так и на окультном MSVC 12

скажите, пожалуйста, это фича, и я что-то пропустил в K&R, или эпическая бага?

p.s. в свою очередь >> довольно православен, и значение отличное от нуля у него только при сдвиге на 0

★★★★★

Последнее исправление: metawishmaster (всего исправлений: 2)

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.

Harald ★★★★★
()
Ответ на: комментарий от Harald

linux64, а оффтопи - 32...

и спасибо за предыдущий ответ, буду знать :)

metawishmaster ★★★★★
() автор топика
Ответ на: комментарий от ziemin

да, это неточность первода - в оригинале было «for (i = a; i < b + 1; i++)», ну и 'a' был в диапазоне [1..32]

metawishmaster ★★★★★
() автор топика
Ответ на: комментарий от mashina

ну да, он только в ILP64 64 бита занимает, но это оффтопик для изотерических машин...

metawishmaster ★★★★★
() автор топика
Последнее исправление: metawishmaster (всего исправлений: 1)

Тут вот есть кое-какое объяснение:

http://stackoverflow.com/questions/3871650/gcc-left-shift-overflow

Соль в том, что шифтинг на больше чем «ширина» типа — это u.b., чем многие и пользуются для оптимизаций. В частности используя только 5 младших бита правого аргумента (в частности на i386 и производных). Что мы собственно в твоём случае и наблюдаем.

TL;DR, твой код эквивалентен:

for (i = 0; i <= 64; i++)
    printf("i = %d; x = 0x%08x\n", i, (0x1 << (i & 0xf)));

beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 3)
Ответ на: комментарий от xaizek

Конечно. Давно так с маскам не позорился. ;)

beastie ★★★★★
()
Ответ на: комментарий от beastie

Соль в том, что шифтинг на больше чем «ширина» типа — это u.b., чем многие и пользуются для оптимизаций

Оптимизации тут совершенно не при чём. Просто инструкция сдвига на разных платформах работает по-разному - где-то (i386) берёт 5 младших бит, где-то обнуляет операнд если сдвиг больше его размера.

slovazap ★★★★★
()

во первых не очень явно,что вы хотели увидеть и почему :-)

далее - отсутствие {} в необходимых местах, для С является «синтаксическим сахаром». Добавьте скобки туда где они должны быть и всё будет ок и всё понятно

MKuznetsov ★★★★★
()
Ответ на: комментарий от metawishmaster

как выяснилось, это undefined behavior

а асм и схемотехнику тот кто выяснял не учил ?

оп. «<<» сдвиг влево, если старший бит вдвинут в огурцы, что должно получится? UB??

это какое-то странное слово, придуманное и продвигаемое манагерами и которое свербит у неофитов и которым люди незнающие язык с одной стороны стращают людей незнающих язык с другой стороны..

ps. одно из слов lisp, sheme, perl заменено на синоним, дабы пожалеть :-))))

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

http://comments.gmane.org/gmane.comp.lang.c++.isocpp.proposals/12148

но эт так, буржуйская фигня от тех, кто составлял стандарт не уча асм и схемотехнику :)

metawishmaster ★★★★★
() автор топика
Последнее исправление: metawishmaster (всего исправлений: 1)
Ответ на: комментарий от MKuznetsov

но если у Вас есть ответ на вопрос топика, то было бы интересно его услышать

metawishmaster ★★★★★
() автор топика

скажите, пожалуйста, это фича

Это UB.

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.