maximum value of int

Discussion in 'C Programming' started by Stanley Rice, Sep 17, 2011.

  1. Stanley Rice

    Stanley Rice Guest

    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.
    Stanley Rice, Sep 17, 2011
    #1
    1. Advertising

  2. Stanley Rice

    Ian Collins Guest

    On 09/17/11 05:07 PM, Stanley Rice wrote:
    > 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.

    --
    Ian Collins
    Ian Collins, Sep 17, 2011
    #2
    1. Advertising

  3. Stanley Rice

    Stanley Rice Guest

    On Sep 17, 1:25 pm, Ian Collins <> wrote:
    > On 09/17/11 05:07 PM, Stanley Rice wrote:
    >
    >
    >
    >
    >
    >
    >
    >
    >
    > > 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.
    >
    > --
    > Ian Collins


    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?
    Stanley Rice, Sep 17, 2011
    #3
  4. Stanley Rice

    Paul N Guest

    On Sep 17, 8:47 am, Stanley Rice <> wrote:
    > On Sep 17, 1:25 pm, Ian Collins <> wrote:
    >
    >
    >
    >
    >
    > > On 09/17/11 05:07 PM, Stanley Rice wrote:

    >
    > > > Hello all

    >
    > > > I don't know it is appropriate to post such a short or easy question
    > > > here.


    That's fine!

    > > > I couldn't understand some line of code abot maximum int value
    > > > as below:

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


    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.
    Paul N, Sep 17, 2011
    #4
  5. Stanley Rice <> writes:
    <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?


    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.

    --
    Ben.
    Ben Bacarisse, Sep 17, 2011
    #5
  6. Stanley Rice

    Eric Sosman Guest

    On 9/17/2011 1:07 AM, Stanley Rice wrote:
    > 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.

    --
    Eric Sosman
    d
    Eric Sosman, Sep 17, 2011
    #6
  7. Stanley Rice

    Joe Pfeiffer Guest

    Stanley Rice <> writes:
    >
    > 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.
    Joe Pfeiffer, Sep 17, 2011
    #7
  8. Joe Pfeiffer <> writes:

    > Stanley Rice <> writes:
    >>
    >> 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?

    <snip>
    > 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.

    --
    Ben.
    Ben Bacarisse, Sep 17, 2011
    #8
  9. Stanley Rice <> writes:
    > On Sep 17, 1:25 pm, Ian Collins <> wrote:
    >> On 09/17/11 05:07 PM, Stanley Rice wrote:
    >> > 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.

    >
    > 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.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Sep 17, 2011
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Schnoffos
    Replies:
    2
    Views:
    1,199
    Martien Verbruggen
    Jun 27, 2003
  2. Hal Styli
    Replies:
    14
    Views:
    1,615
    Old Wolf
    Jan 20, 2004
  3. Amit
    Replies:
    2
    Views:
    411
  4. Pugi!
    Replies:
    2
    Views:
    94
    Steve
    Feb 12, 2007
  5. phanhuyich
    Replies:
    4
    Views:
    257
Loading...

Share This Page