C weird bit offset behavior

Why does the following code compiled with gcc print "ffffffff 0" instead of "0 0"? Bits are shifted to the right by 32 positions in both instructions. This doesn't make much sense since x == 32, but still this weird result happens ...

#include <stdio.h> int main(void) { int x = 32; printf("%x\n", 0xffffffff >> x); printf("%x\n", 0xffffffff >> 32); return 0; } 

Edit: enter image description here

Edit2: Yes, the compiler warned me. But it's not that. I use 0xffffffff as a mask, which I reset with a variable. For example, when I have a bitrate of 8, I want 0xffffff (and he does it). When I reset the bit from 31, I want 0x1 as a result (and it does this). And when I reset the bit from 32, it gives me 0xffffffff (instead of 0, which is beahaviour when I have 32 as a literal, not a variable). It is strange and for my purpose it is really inconvenient to make a special case for 32, since it should give 0 (and this happens, but only when 32 is a literal)

+5
source share
5 answers

Assuming that int and unsigned int are 32 bits wide, the integer constant 0xffffffff is of type unsigned int.

The right shift of an integer with a value greater than or equal to the width of the integer will result in undefined 1 behavior.

This happens in both cases in your example.

Update:

Undefined behavior means that anything can happen. Getting the value 0xffffffff instead of 0 corresponds to this behavior.

You cannot shift the width of an integer type, because that says it in the standard. You should check if the value is greater than or equal to the width of the type you are working with.


1 (Quoted from: ISO / IEC 9899: 201x 6.5.7 Bitwise shift operators 3)
If the value of the right operand is negative or greater than or equal to the width of the advanced left operand, the behavior is undefined.

+6
source

Edit2: Yes, the compiler warned me. But it's not that. I am using 0xffffffff as a mask, which I am combining with a variable. For example, when I bitrate with 8, I want 0xffffff (and he does it). When I reset the bit from 31, I want 0x1 as a result (and it does this). And also when I have a bitrate of 32, it gives me 0xffffffff (instead of 0, that beahaviour when I have 32 as a literal and not a variable). this is strange and for my purpose it is really strange to make a special case for 32, as it should give 0 (and this happens, but only when 32 is literal)

Yes, it is, very. At that moment when you try to move it to 32, which, as your compiler said >= width you call undefined behavior. At the moment, all bets are disabled, no more assumptions as to what the program will do can be made. It should not print anything or format your disk. So this is not "weird."

+4
source

In addition to the undefined behaviors that other answers talk about, the difference in result comes from the GCC, which selects the second bit-shift.

If you parse the code using the -S flag, you may notice that only one shrl command is shrl :

 subq $16, %rsp movl $32, -4(%rbp) movl -4(%rbp), %eax movl $-1, %edx movl %eax, %ecx shrl %cl, %edx movl %edx, %eax movl %eax, %esi movl $.LC0, %edi movl $0, %eax call printf movl $0, %esi movl $.LC0, %edi movl $0, %eax call printf movl $0, %eax 

The compiler saw that he could calculate the second bitshift at compile time, since he would never change or replace the calculation based on its result, here 0 .

+2
source

If you are targeting an environment with a 32-bit int, then an offset of 32 or more bits is Undefined Behavior :

if the value of the correct operand is negative or greater than or equal to the number of bits in the advanced left operand, the behavior is undefined.

It is your responsibility as a programmer to avoid calling UB.

0
source

It depends on the compiler. But in your example, in the first case, x signed, so the shift is arithmetic (the leftmost bit is again inserted on the left). In the second case, the literal 32 treated as unsigned, so the shift becomes logical ( 0 inserted on the left). This explains the result of ffffffff 0 .

-1
source

Source: https://habr.com/ru/post/1258746/


All Articles