10

I want to get the values of INT_MIN and INT_MAX. I've tried ~0 and ~0 >> 1 since the leftmost bit is a sign bit but I got -1 for both of them.

It's so confused that why ~0 doesn't turn out to be 0xffffffff and ~0 >> 1 to be 0x7fffffff?

phuclv
  • 37,963
  • 15
  • 156
  • 475
dastan
  • 1,006
  • 1
  • 16
  • 36
  • ~0 is 0xffffffff, which is the binary representation of -1. Minint would be 0x80000000 if memory serves me right. – Mattias Åslund Apr 20 '14 at 08:51
  • @MattiasÅslund it's 0x80000000 only if int is 32 bits and using 2's complement – phuclv Apr 20 '14 at 09:02
  • If you are unaware of concept of signed and unsigned shifts read this [right shift on negative number](http://stackoverflow.com/a/15457908/1673391) *note this is Java link and behavior of operators are different in both languages* but still two diagrams clearly shows what is singed and unsigned right shifts.. – Grijesh Chauhan Apr 20 '14 at 09:30
  • User3505816 I forgot to add in my answer that `~0` itself implementation defined Read [Calculating Ranges of Data Types in C](http://stackoverflow.com/questions/17796041/calculating-ranges-of-data-types-in-c#) – Grijesh Chauhan Apr 21 '14 at 07:12

7 Answers7

25

Use:

~0U >> 1

Suffix 'U' for unsigned shift behavior.

so, confused that why not ~0 turns out to be 0xffffffff?

See, what is 0 say in four bytes representation:

BIT NUMBER    31                                     0
               ▼                                     ▼
number bits    0000 0000 0000 0000 0000 0000 0000 0000 
               ▲                                     ▲ 
              MSB                                   LSB



LSB - Least Significant Bit (numbered 0)
MSB - Most  Significant Bit (numbered 31) 

Now ~ is bitwise not operator then flips all bits in 0 as:

BIT NUMBER    31                                     0
               ▼                                     ▼
number bits    1111 1111 1111 1111 1111 1111 1111 1111
               ▲                                     ▲ 
              MSB                                   LSB

Because of MSB = 1 this representation is treated as negative number and its magnitude is find using 2'complement math that is -1.

How?

What is 1 ? it is:

number bits    0000 0000 0000 0000 0000 0000 0000 0001 
               ▲                                     ▲ 
              MSB                                   LSB

1's complement of 1

number bits    1111 1111 1111 1111 1111 1111 1111 1110
               ▲                                     ▲ 
              MSB                                   LSB

2'complement? Add 1 in one's complement, that is:

number bits    1111 1111 1111 1111 1111 1111 1111 1111
               ▲                                     ▲ 
              MSB                                   LSB

this same as when you gets ~0 ? that is why you are getting -1 output.

Now >> shift operator?

In most implementation of C >> operator is defined as an arithmetic right shift, which preserves the sign bit MSB. So ~0 >> 1 is noting but -1 remains same.

6.5.7 [Bitwise shift operators]

5 The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

You requirement is what is called unsigned right shift >> and the behavior you needed can be find using unsigned number that is why I suffixed U as 0U.

How to print INT_MIN and INT_MAX?

Because printing INT_MIN and INT_MAX is bit tricky(because of undefined and implementation behavior of setting MSB and bit-overflow) in C so I have written a code as follows:

#include <stdio.h>
#include<limits.h> /* include for CHAR_BIT */
int main(){
  int my_int_min = 1U << ((sizeof(int) * CHAR_BIT) - 1);
  int my_int_max = ~0U >> 1;
  printf("INT_MIN  = %d\n", my_int_min);
  printf("INT_MAX  = %d\n", my_int_max);
  return 0;
}

See it executing @codepad, it output is:

INT_MIN  = -2147483648
INT_MAX  = 2147483647 

How does this code work?

Note for 32-bit number range is [-2147483648, 2147483647] that is equals to [-231, 231 -1 ].

INT_MIN: -231 == -2147483648 is:

    1000 0000 0000 0000 0000 0000 0000 0000 
    ▲                                     ▲ 
    MSB                                   LSB

In expression 1U << ((sizeof(int) * CHAR_BIT) - 1), I shifts first bit the LSB(that is 1) to left most side at MSB, And because in C, setting signed bit is undefined behavior when operand is singed type so I used unsigned one 1U.

6.5.7 [Bitwise shift operators]

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. 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. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

Another point to note is I used CHAR_BIT a standard macro defined in limits.h that tells number of bits in one char in a C implementation (remember: A char is always one byte size but number of bits in one bytes can be different on different system not always guaranteed to be 8).

INT_MAX: 231 -1 == 2147483647

    0111 1111 1111 1111 1111 1111 1111 1111
    ▲                                     ▲ 
    MSB                                   LSB
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
  • Your answer is quite clear, but still I have a doubt: I've heard that an INT isn't always four bytes, but can you describe more concretely when a byte doesn't consist of eight bits? – dastan Apr 20 '14 at 11:31
  • 1
    @user3505816 You asked two doubts actually (1) INT may not be 4 bytes it can be 2 byte or 8 bytes it depends on system's architecture and compiler To know size of int in bytes on your system use this code `printf("%zu \n", sizeof (int));` And If you need specifically 4 byte integer use datatype `int32_t` as `int32_t i;` similarly for 2 bytes use `int16_t` ....(2) One byte may not is consist of 8 bits that is why CHAR_BIT exists read [What is CHAR_BIT?](http://stackoverflow.com/questions/3200954/what-is-char-bit) – Grijesh Chauhan Apr 20 '14 at 11:48
  • @user3505816 Read Jonathan Leffler's [answer](http://stackoverflow.com/a/589685/1673391) – Grijesh Chauhan Apr 20 '14 at 11:53
4

0 is of type int. So are ~0 and ~0 >> 1 because of int type promotion

~0 has all 1s in its bit pattern and it's -1 in 2's complement, which is the default representation of most modern implementations.

Right shift in C is implementation defined. But most implementations define >> as arithmetic shift when the type is signed and logical shift when the type is unsigned

Since ~0 is int, which is a signed type, ~0 >> 1 will be an arithmetic shift right. Hence the value is sign extended, cause the value to be all 1s

You need to do unsigned(~0) >> 1 or ~0U

There are no ways to get INT_MIN and INT_MAX portably because in C there are 3 different signed type implementations beside trap representations and padding bits. That's why standard libraries always define INT_MIN and INT_MAX directly with the values

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • `unsigned(~0)` and `~0u` are different if non 2's complement; `~0u` is the intended version. – M.M Dec 22 '14 at 03:27
1

numbers are stored in 2's compliment so ~0 is 0XFFFFFFFF which is -1 .
so FFFFFFF(1111) >>1 gives (1111)FFFFFFF = 0XFFFFFFFF = -1.

When shifting an unsigned value, the >> operator in C is a logical shift. When shifting a signed value, the >> operator is an arithmetic shift.
So , ~0U >> 1 gives (1111)FFFFFFF = 0XFFFFFFFF .

Aseem Goyal
  • 2,683
  • 3
  • 31
  • 48
1

~0 is -1. Every C implementation that you're likely to run into uses two's complement for signed integers, so 0xffffffff is -1 (assuming 32-bit integers). ~0 >> 1 is the equivalent of dividing -1 by 2; since we're doing integer arithmetic, the result is -1.

user3553031
  • 5,990
  • 1
  • 20
  • 40
  • `~0 >> 1` is unspecified, as all bit shifts on negative integers. If you still get -1 it's because the assembly emitted by your compiler asks for sign extension on bit shift. – Matteo Italia Apr 20 '14 at 10:15
  • True. But compilers are more likely to output -1 for `~0>>1` than anything else. Even though by the standard, they're technically allowed to post the entire contents of your hard drive to stackoverflow when they encounter something like that. – user3553031 Apr 20 '14 at 15:11
  • Of course nobody goes that far into UB (and this is not UB, but implementation-specific behavior). The point is that usually compilers are more inclined to do whatever the right shift assembly instruction on the current platform do. If both arithmetic and bitwise shift are available, it boils down to an implementation's choice. – Matteo Italia Apr 20 '14 at 15:57
1

The value of an all bit set int depends on the sign representation that your platform has for int. This is why the macros INT_MIN and INT_MAX were invented, there is no way of computing these values in a portable way.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
1

Based on the wikipedia article, C normally implements an arithmetic shift. That means that when you right-shift the quantity 0xffffffff, the left-most bit (sign bit) of 1 will be preserved, as you observe.

However, Wikipedia also mentions the following, so you will get a logical shift (result of 0x7fffffff) if you use the unsigned type.

The >> operator in C and C++ is not necessarily an arithmetic shift. Usually it is only an arithmetic shift if used with a signed integer type on its left-hand side. If it is used on an unsigned integer type instead, it will be a logical shift.

merlin2011
  • 71,677
  • 44
  • 195
  • 329
1

On a 32bit system, 0 is 0x00000000. ~ is the bitwise not operator, which turns every 0 bit to 1 and vice versa. Therefore, ~0 (~0x00000000) gives 0xffffffff.

This in turn is interpreted as -1 in Two's complement.

Olaf Dietsche
  • 72,253
  • 8
  • 102
  • 198