Frage

int main(){
    ll a=pow(2,32);
    cout <<a<<endl;
    cout << (-1<<1)<<endl;
    printf("%x",-1<<1);
}

For the above code, I am getting following output:

4294967296
-2
fffffffe

4294967296 in decimal is equal to fffffffe in hexadecimal which is basically 2^32. Why is printf and cout behaving differently? And how exactly does this shift works?

War es hilfreich?

Lösung

The printf format flag %x means to print an integral value in hexadecimal.

There is a stream manipulator to accomplish this as well (std::hex), but you're not using that. When you output an integral value to a stream with no manipulators, it outputs in base 10.

See here for more information about the printf format flags, and here for information about stream manipulators.

The shift operator << works as described in the C++03 Standard (14882:2003):

5.8 Shift operators

1/ The shift operators << and >> group left-to-right. shift-expression: additive-expression shift-expression << additive-expression shift-expression >> additive-expression

The operands shall be of integral or enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. 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.

2/ The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 multiplied by the quantity 2 raised to the power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long, UINT_MAX+1 otherwise.

[Note: the constants ULONG_MAX and UINT_MAX are defined in the header ). ]

In your case, the value -1 in binary is all 1s in every bit. For a 32 bit value, then:

11111111 11111111 11111111 11111111 

If you shift this left 1 bit using <<, you get:

11111111 11111111 11111111 11111110 

Which in base 10 is -2. Since the operation -1<<1 uses a negative number for the LHS, the entire expression is of a signed (not unsigned) type.

Andere Tipps

First,

fffffffe in hexadecimal which is basically 2^32

is wrong. FFFFFFFE = 4294967294, which is 2^32 - 2 (for unsigned integers), or -2 (for 32-bit signed integers in 2's complement).

Second, printf("%x", ...) will print an unsigned hexadecimal integer (that is an unsigned int), which is 32-bits on most modern systems. long long a = 2 << 32 requires a 64-bit integer to properly store it (or, more precisely, at least a 33-bit integer), so when you use cout << a, you are calling ostream& operator<<(ostream&, long long), which has the proper type. That is, you are running into an overflow issue because of the type used by the printf specifier vs the strong type used by the C++ operator<< overload.

This code invokes undefined behavior since you are trying to left shift a negative number, the draft C++11 Standard section 5.8 Shift operators says(emphasis mine):

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1×2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

This is also the same for the draft C99 standard section 6.5.7 Bitwise shift operators

It is also undefined behavior to specify an invalid conversion specifier to printf, you are specifying %x which expect an unsigned int but the result is signed. The C99 draft in section 7.19.6.1 The fprintf function paragraph 9 says:

If a conversion specification is invalid, the behavior is undefined.248) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

%x formats the output to show the value in hexadecimal, so you should pass std::hex to cout to do a same thing:

std::cout << std:::hex << (-1<<1) << endl;
             ^^^^^^^^^

This will produce the correct same answer as you need to tell it to print in hex

cout << hex<<(-1<<1)<<endl;
printf("%x",-1<<1);

%x is hex where as the cout are just outputting the numbers (int) directly -1 is 0xFFFFFFFF shift that to the left you have to add in a 0 ie so the last F (in binary is 1111 becomes 1110 ie E The other guys answer your points clearer I think....

For the sake of readbility let's use a signed 8bit integer:

-1 bitwise is 11111111

now doing a left-shift by 1:

-1 << 1

you get:

11111110 which is -2

However using the the conversion specifier %x tells printf() to tread 11111111 as un-signed so it prints out fe.

The first case is valid: pow(2,32) returns the exact value 232 as a double, which remains exact when you convert it to long long (I'm assuming that's what the mystery ll type is). Printing this with cout is perfectly valid.

In the case of (-1<<1), left-shifting a negative number yields undefined behavior. Even if the compiler does define it as -2 (most will), it's also undefined behavior to pass a negative number for use with printf's %x specifier (which requires an unsigned type).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top