Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does -1 >> 1 and 0xFFFFFFFF >> 1 produce different results?

I am trying to make a test to tell whether my PC performs arithmetic or logical right shift by right-shifting hexadecimal FFFFFFFF by 1.

I know that an integer -1 reads as FFFFFFFF in hexadecimal since it is the two's complement of 1. Right-shifting -1 by 1 results in FFFFFFFF and shows the PC performed arithmetic right shift.

But if I just type in 0xFFFFFFFF >> 1, it resulted in 7FFFFFFF and shows that the PC performed logical right shift instead. Why did that happen? See for the code below that produced the results:

#include    <stdlib.h>
#include    <stdio.h>

int main ( int argc, char *argv[] )
{
    printf ( "%x >> 1 = %x\n", -1, -1 >> 1 );
    printf ( "%x >> 1 = %x\n", 0xffffffff, 0xffffffff >> 1 );

    return EXIT_SUCCESS;
}

The program's output was:

ffffffff >> 1 = ffffffff
ffffffff >> 1 = 7fffffff
like image 969
vxs8122 Avatar asked Jul 10 '14 02:07

vxs8122


2 Answers

It is not an assumption. What type do you think 0xffffffff is ? According to the C standard, 6.4.4.1 Integer constants, the type of the expression of a hexadecimal constant (preceded with 0x) is the first of the following which can applicably hold the represented value:

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

On your platform, 0xFFFFFFFF cannot be represented as int because int is 32 bits and only 31 bits express quantity in signed int (the standard dictates one bit is reserved for sign). The next type, unsigned int, is therefore used. Therefore no sign bit is present to extended with the shift operation, which is thereby logical rather than arithmetic.

It may not be apparent how I concluded int was 32 bits on your platform. Indeed I could not make that assumption were it not for the first line, which arithmetic-right-shifts the value of -1. The result of that shift, dumped as %x, was 0xFFFFFFFF. Had int been native 64-bits that should dump 0xFFFFFFFFFFFFFFFF instead. Without that prior knowledge, no single type conclusion of 0xFFFFFFFF could be assumed since it may well be representable as a standard signed int of width 64-bits (63+1) with value 0x00000000FFFFFFFF. The resulting shift would produce the same output you see now, thereby introducing an alternative to that postulated above.

like image 73
WhozCraig Avatar answered Oct 01 '22 12:10

WhozCraig


Your main question is: is 0xffffffff unsigned?

From C11 §6.4.4.1 Integer constants

The type of an integer constant is the first of the corresponding list in which its value can be represented.

enter image description here

The output of your first printf line suggests that int is 32-bit on your machine. Thus it can not represent 0xffffffff, it must be unsigned.

like image 39
Yu Hao Avatar answered Oct 01 '22 12:10

Yu Hao