maximum value of int

S

Stanley Rice

Hello all

I don't know it is appropriate to post such a short or easy question
here. I couldn't understand some line of code abot maximum int value
as below:

#define INT_MAX (((unsigned)-1) >> 1)

The first time I saw it, I was confused why it could pass the
examination of the compiler. I try to make a bit modification, say
#define INT_TEST ((unsigned) - 1)
This time, the compiler also shuts its mouth, but when I try
#define INT_TEST (unsigned)
The compiler begins to shout to me.

I'm confused about why the type itself, i.e unsigned, could do
subtration. And it could generate an integer. But when I leave the
type alone, the compiler tries to stop me.
 
I

Ian Collins

Hello all

I don't know it is appropriate to post such a short or easy question
here. I couldn't understand some line of code abot maximum int value
as below:

#define INT_MAX (((unsigned)-1)>> 1)

The first time I saw it, I was confused why it could pass the
examination of the compiler. I try to make a bit modification, say
#define INT_TEST ((unsigned) - 1)
This time, the compiler also shuts its mouth, but when I try
#define INT_TEST (unsigned)
The compiler begins to shout to me.

I'm confused about why the type itself, i.e unsigned, could do
subtration. And it could generate an integer. But when I leave the
type alone, the compiler tries to stop me.

(unsigned)-1 is a cast, not a subtraction.
 
S

Stanley Rice

(unsigned)-1 is a cast, not a subtraction.

Oh yes, I got it! Thanks a lot. Now I want to know whether the
underlying representation (bit stream) of -1 in type int and type
unsigned are the same or not, suggesting type int is in 32 bit in my
machine. I guess the underlying representation of digit -1 is the
same, say,
1111 1111 1111 1111 1111 1111 1111 1111 (FFFFFFFF)
When we treat it as an signed int, it is decoded as a digit as int_val
= -1, and when we treat it as an unsigned int, it is decoded as a
digit as unsigned_val = 4294967295, could you tell me if my guess is
right or not?

If my assumption is right, then I am confused about the different
result of the following lines:
printf("%u\n", (unsigned)-1 >> 1); // 1
printf("%u\n", (unsigned)(-1 >> 1)); // 2
printf("%u\n", (unsigned)(-1 >> 2)); // 3
printf("%u\n", (unsigned)-1); // 4
The statement 1 prints 2147483647, which is what i want. But statement
2, 3, 4 all print the same, 4294967295. That is what I am confused
about. Why statement 1 and statement 2 generate different results? And
why statement 2, 3 and 4 generate the same result?
 
P

Paul N

That's fine!

If I remember correctly, it is up to the compiler to define INT_MAX.
When people are writing compilers, they are writing them for a
specific system and so they can use their knowledge of details of the
system. When *you* are writing programs, you can if you want to use
your knowledge of details of the system, but the point of C is to
allow a program to be run on any computer with a C compiler and so it
is often encouraged to make your programs "portable", ie not dependent
on the detailsof the particular system. So the code above (which I am
guessing you found in a header file of the compiler) is not
necessarily the sort of thing you'd write yourself.

(snip)
Oh yes, I got it! Thanks a lot. Now I want to know whether the
underlying representation (bit stream) of -1 in type int and type
unsigned are the same or not, suggesting type int is in 32 bit in my
machine. I guess the underlying representation of digit -1  is the
same, say,
    1111 1111 1111 1111 1111 1111 1111 1111 (FFFFFFFF)
When we treat it as an signed int, it is decoded as a digit as int_val
= -1, and when we treat it as an unsigned int, it is decoded as a
digit as unsigned_val = 4294967295, could you tell me if my guess is
right or not?

If my assumption is right, then I am confused about the different
result of the following lines:
    printf("%u\n", (unsigned)-1 >> 1);      // 1
    printf("%u\n", (unsigned)(-1 >> 1));    // 2
    printf("%u\n", (unsigned)(-1 >> 2));    // 3
    printf("%u\n", (unsigned)-1);           // 4
The statement 1 prints 2147483647, which is what i want. But statement
2, 3, 4 all print the same, 4294967295. That is what I am confused
about. Why statement 1 and statement 2 generate different results? And
why statement 2, 3 and 4 generate the same result?

I think your problems here stem from the fact that in 2 and 3, the
number -1 is treated as an int, shifted and only then converted to an
unsigned. I'm guessing that when you shift a negative number you get
another negative number, so 1s are coming in at the front, leaving the
number unchanged as all 1s. It's a similar problem to:

(double) (1/3)

which gives a result of 0 as the division is done as integers and only
then converted to a double.

I'n not an expert on all this, though.
 
B

Ben Bacarisse

Stanley Rice said:
Oh yes, I got it! Thanks a lot. Now I want to know whether the
underlying representation (bit stream) of -1 in type int and type
unsigned are the same or not, suggesting type int is in 32 bit in my
machine. I guess the underlying representation of digit -1 is the
same, say,
1111 1111 1111 1111 1111 1111 1111 1111 (FFFFFFFF)
When we treat it as an signed int, it is decoded as a digit as int_val
= -1, and when we treat it as an unsigned int, it is decoded as a
digit as unsigned_val = 4294967295, could you tell me if my guess is
right or not?

On must 32-bit machines, all ones represents either an unsigned int of
4294967295 or a signed int of -1.
If my assumption is right, then I am confused about the different
result of the following lines:
printf("%u\n", (unsigned)-1 >> 1); // 1
printf("%u\n", (unsigned)(-1 >> 1)); // 2
printf("%u\n", (unsigned)(-1 >> 2)); // 3
printf("%u\n", (unsigned)-1); // 4
The statement 1 prints 2147483647, which is what i want. But statement
2, 3, 4 all print the same, 4294967295. That is what I am confused
about. Why statement 1 and statement 2 generate different results? And
why statement 2, 3 and 4 generate the same result?

C leaves the meaning of shifting a signed int with a negative value up
to the individual implementation. Your compiler chooses to use a"
sign-extending" shift. Thus -1 >> n where n < the bit width of the
integer will always be -1.

Do you have a book on C? Without a good one you might spend a lot of
time wondering about questions like this. A good book could answer many
of them at once.
 
E

Eric Sosman

Hello all

I don't know it is appropriate to post such a short or easy question
here. I couldn't understand some line of code abot maximum int value
as below:

#define INT_MAX (((unsigned)-1)>> 1)

As an aside to the explanations others have provided, note that
this is not a valid way to define the INT_MAX macro in <limits.h>.
Although it will (very probably) have the correct numeric value, it
lacks two features required of the INT_MAX from <limits.h>:

- It is not an expression whose value the preprocessor can
compute, making it unusable in #if directives.

- Once evaluated, it is of the wrong type: `unsigned int'
instead of plain `int', a.k.a. `signed int'.

If your code does not include <limits.h>, directly or indirectly,
you are of course free to use the identifier INT_MAX however you like.
But it's a Very Bad Idea to use a Standard-described identifier in a
non-standard way, leading mostly to confusion and chaos. If you're
studying this person's code to improve your knowledge of C, be warned
that the author's own grasp of C may not be all that firm.
 
J

Joe Pfeiffer

Stanley Rice said:
If my assumption is right, then I am confused about the different
result of the following lines:
printf("%u\n", (unsigned)-1 >> 1); // 1
printf("%u\n", (unsigned)(-1 >> 1)); // 2
printf("%u\n", (unsigned)(-1 >> 2)); // 3
printf("%u\n", (unsigned)-1); // 4
The statement 1 prints 2147483647, which is what i want. But statement
2, 3, 4 all print the same, 4294967295. That is what I am confused
about. Why statement 1 and statement 2 generate different results? And
why statement 2, 3 and 4 generate the same result?

My experience has always been that when experimenting with seeing it
patterns, I'm better off printing them in hexadecimal with a %08x (for a
32 bit system).

Anyway:

The first one is taking a -1, interpreting it as unsigned, and then
right-shifting one bit. Since it's unsigned, it shifts 0s in from the
left, so you get 7fffffff.

The other three are all doing the shift first (well, there is no shift
for the fourth one, but we'll see in a moment that that doesn't
matter). Because you're shifting a negative number, the shift is
shifting copies of the sign bit in. -1 is 0xffffffff; -1 right-shifted
by one (but shifting a 1 in on the left) is still 0xffffffff, and -1
right-shifted by two, but still copying the sign bit in, is still
0xffffffff.

IIRC, this behavior is not guaranteed by the standard.
 
B

Ben Bacarisse

The first one is taking a -1, interpreting it as unsigned, and then
right-shifting one bit. Since it's unsigned, it shifts 0s in from the
left, so you get 7fffffff.

Minor quibble: the phrase "interpret as unsigned" might suggest that the
bits of -1 are treated as if they were unsigned, whereas the standard
calls this a conversion (from signed int to unsigned int) and it is
defined in terms of modular arithmetic such that the result *must* be
UINT_MAX (all value bits set to 1).

The difference is that on, for example, a sign+magnitude machine
(unsigned)-1 must still be UINT_MAX.

And just to round it off, what you said is perfectly correct on most
machines. The rules of signed to unsigned conversion are such that most
implementations can just interpret the bit pattern as if it were
unsigned and no actual code is needed to do the conversion.
The other three are all doing the shift first (well, there is no shift
for the fourth one, but we'll see in a moment that that doesn't
matter). Because you're shifting a negative number, the shift is
shifting copies of the sign bit in. -1 is 0xffffffff; -1 right-shifted
by one (but shifting a 1 in on the left) is still 0xffffffff, and -1
right-shifted by two, but still copying the sign bit in, is still
0xffffffff.

IIRC, this behavior is not guaranteed by the standard.

The first part is guaranteed, but the second is implementation defined.
This one a machine can't easily do sign-extended shifts, a plain shift
can be used.
 
K

Keith Thompson

Stanley Rice said:
Oh yes, I got it! Thanks a lot. Now I want to know whether the
underlying representation (bit stream) of -1 in type int and type
unsigned are the same or not, suggesting type int is in 32 bit in my
machine. I guess the underlying representation of digit -1 is the
same, say,
1111 1111 1111 1111 1111 1111 1111 1111 (FFFFFFFF)
When we treat it as an signed int, it is decoded as a digit as int_val
= -1, and when we treat it as an unsigned int, it is decoded as a
digit as unsigned_val = 4294967295, could you tell me if my guess is
right or not?

The validity of the expression has (almost) nothing to do with how
signed and unsigned integeres are represented. That's not to say that
you shouldn't be curious about the representation, but it's not directly
relevant here.

1 is an expression of type int, with the obvious value.

-1 is an expression consisting of the unary "-" operator applied to 1.
It's also of type int, also with the obvious value.

(unsigned)-1 is a cast expression; the "(unsigned)" part is a cast
operator. It takes the value of the expression -1 and converts it
from type int to type unsigned int ("unsigned int" and "unsigned"
are simply two names for the same type). As I mentioned, that
conversion is not defined in terms of how either int or unsigned
int is represented; it's defined entirely in terms of *values*.
The result of this particular conversion is defined in the C
standard, section 6.3.1.3, paragraph 2:

Otherwise, if the new type is unsigned, the value is converted
by repeatedly adding or subtracting one more than the maximum
value that can be represented in the new type until the value
is in the range of the new type.

The "maximum value that can be represented in the new type" is
UINT_MAX. The result of the conversion is computed, in this case,
by adding UINT_MAX+1 to -1, which yields UINT_MAX. In general,
the value -1 converted to any unsigned type yields the maximum
value of that unsigned type.

Then we right-shift the result by 1 bit (>> 1), yielding UINT_MAX/2
(truncated). On most systems, that's going to be the value of
INT_MAX (though, as Eric Sosman points out, it's not of the right
type, nor is it suitable for use as the system's definition of
INT_MAX). It's possible for INT_MAX *not* to equal (((unsigned)-1)>>
1), but that can happen only in the presence of padding bits,
which are rare in modern systems.

(On a typical 32-bit system, UINT_MAX is 2**32-1, or 0xffffffff,
or 4294967295, and INT_MAX is 2**31-1, or 0x7fffffff, or 2147483647;
other values are possible. The "**" denotes expontiation; C doesn't
actually have a "**" operator.)

Now has it happens, the rule for converting signed int to unsigned int
works out very well for a typical 2's-complement system. The generated
code for the conversion doesn't really work by "repeatedly adding or
subtracting one more than the maximum value that can be represented in
the new type until the value is in the range of the new type". It does
the exact equivalent -- which happens to mean just copying or
reinterpreting the bits that make up the representation. An
implementation for a 1s'-complement or sign-and-magnitude system still
has to follow the same rule for conversion, even though it's less
convenient. The standard's definition of the conversion works entirely
in terms of values; the reason that definition is the way it is is that
it works well with the most common representation scheme. (And that's
why the standard's wording seems clumsy; it's describe something that
was originally about reinterpreting the representation, but doing so in
terms of mathematical values.)
If my assumption is right, then I am confused about the different
result of the following lines:
printf("%u\n", (unsigned)-1 >> 1); // 1
printf("%u\n", (unsigned)(-1 >> 1)); // 2
printf("%u\n", (unsigned)(-1 >> 2)); // 3
printf("%u\n", (unsigned)-1); // 4
The statement 1 prints 2147483647, which is what i want. But statement
2, 3, 4 all print the same, 4294967295. That is what I am confused
about. Why statement 1 and statement 2 generate different results? And
why statement 2, 3 and 4 generate the same result?

If the left operand of a ">>" operator is negative, the result is
implementation-defined (C99 6.5.7p5). Shift operators are primarily
intended for use with unsigned, or at least non-negative, operands.
You could probably figure out why your lines 2 and 3 are producing
the results you're seeing, but I don't think the answer would be
very useful.

Your line 4 is printing the value of UINT_MAX, as explained above.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top