Why, warning: comparison between signed and unsigned integer expressions?

Discussion in 'C Programming' started by Lox, May 29, 2012.

  1. Lox

    Lox Guest

    Hello all experts. If I compile the following code (small example) I
    get "warning: comparison between signed and unsigned integer
    expressions".

    void test(void)
    {
    uint8_t a;
    uint32_t i;

    a = 10;

    for(i = 0; i < (a + 1); i++)
    {

    }
    }

    But the following code doesn't give that warning:


    void test(void)
    {
    uint8_t a;
    uint32_t i;

    a = 10;

    for(i = 0; i < (uint32_t)(a + 1); i++)
    {

    }
    }

    What is going on here? Why does the compiler think (a + 1) is signed?
     
    Lox, May 29, 2012
    #1
    1. Advertising

  2. Lox

    Ike Naar Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 2012-05-29, bartek szurgot <> wrote:
    > hi,
    >
    > On 05/29/2012 08:15 AM, Lox wrote:
    >> Hello all experts. If I compile the following code (small example) I
    >> get "warning: comparison between signed and unsigned integer
    >> expressions".
    >>
    >> void test(void)
    >> {
    >> uint8_t a;
    >> uint32_t i;
    >>
    >> a = 10;
    >>
    >> for(i = 0; i < (a + 1); i++)
    >> {
    >>
    >> }
    >> }

    >
    > what compiler are you using? i'm unable to reproduce this warning on
    > gcc-4.[567]


    Use the -Wextra option.
     
    Ike Naar, May 29, 2012
    #2
    1. Advertising

  3. Lox

    Ike Naar Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 2012-05-29, Lox <> wrote:
    > Hello all experts. If I compile the following code (small example) I
    > get "warning: comparison between signed and unsigned integer
    > expressions".
    >
    > void test(void)
    > {
    > uint8_t a;
    > uint32_t i;
    >
    > a = 10;
    >
    > for(i = 0; i < (a + 1); i++)
    > {
    >
    > }
    > }


    Integer promotions.
    In i < (a + 1), a is promoted to an int because, apparently on your
    implementation, int can represent all values of type uint8_t.

    The promoted a (int) and 1 (int) are added, yielding int (a + 1) .
    The operands of the comparison are uint32_t and int, hence the warning.

    > But the following code doesn't give that warning:
    >
    >
    > void test(void)
    > {
    > uint8_t a;
    > uint32_t i;
    >
    > a = 10;
    >
    > for(i = 0; i < (uint32_t)(a + 1); i++)
    > {
    >
    > }
    > }


    Here the int expression (a + 1) is explicitly converted
    to uint32_t, so the comparison is between two uint32_t's.
     
    Ike Naar, May 29, 2012
    #3
  4. Lox

    Lox Guest

    I get the same warning when i use:

    void test(void)
    {
    uint8_t a;
    uint32_t i;
    a = 10;
    for(i = 0; i < (a + UINT8_C(1)); i++)
    {
    }
    }

    and also on:

    void test(void)
    {
    uint8_t a;
    uint32_t i;
    a = 10;
    for(i = 0; i < ((uint8_t)a + (uint8_t)1); i++)
    {
    }
    }

    I'm using Ride7 IDE from Raisonance. It uses some form of GCC for ARM
    (arm-none-eabi-gcc.exe).

    But I think it is solved now when I understand that char and short
    gets promoted to int. Thank you all.

    On May 29, 9:21 am, bartek szurgot <> wrote:
    > hi,
    >
    > On 05/29/2012 08:15 AM, Lox wrote:


    > what compiler are you using? i'm unable to reproduce this warning on
    > gcc-4.[567] and clang-3.0, but id say that a+1 is uint8_t+int, that
    > gives int, thus signed. try a+1u instead.
     
    Lox, May 29, 2012
    #4
  5. Lox

    BartC Guest

    "Ike Naar" <> wrote in message
    news:...
    > On 2012-05-29, Lox <> wrote:
    >> Hello all experts. If I compile the following code (small example) I
    >> get "warning: comparison between signed and unsigned integer
    >> expressions".
    >>
    >> void test(void)
    >> {
    >> uint8_t a;
    >> uint32_t i;
    >>
    >> a = 10;
    >>
    >> for(i = 0; i < (a + 1); i++)
    >> {
    >>
    >> }
    >> }

    >
    > Integer promotions.
    > In i < (a + 1), a is promoted to an int because, apparently on your
    > implementation, int can represent all values of type uint8_t.


    So all the discussion in the recent thread ("condition true or false? ...")
    about mixed arithmetic being unsigned, isn't always true?

    (Yes I've now read 6.3.1.8. But why would C care more about preserving
    possible negative values of a wider int, than the negative values of a
    narrower int? The mixed arithmetic rule could have been more consistent.)

    --
    Bartc
     
    BartC, May 29, 2012
    #5
  6. Lox

    Lox Guest

    I also tested the integer promotion in the following examples.

    uint32_t x;
    uint8_t y;

    x = 255;
    y = x + UINT8_C(1);

    y is 256 and not 255 as one would think.

    but in:

    uint32_t x;
    uint8_t y;

    x = 255;
    y = (u8_t)(x + UINT8_C(1));

    y is 255

    :)
     
    Lox, May 29, 2012
    #6
  7. Lox

    James Kuyper Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 05/29/2012 03:56 AM, Ike Naar wrote:
    ....
    > In i < (a + 1), a is promoted to an int because, apparently on your
    > implementation, int can represent all values of type uint8_t.


    That's not specific to his implementation. uint8_t is an exact-sized
    type, so UINT8_MAX has to be 255. An implementation where CHAR_BITS>8
    cannot implement uint8_t, and therefore must NOT provide it. INT_MAX is
    not allowed to be less than 32767, so uint8_t always promotes to int.
    --
    James Kuyper
     
    James Kuyper, May 29, 2012
    #7
  8. Lox

    James Kuyper Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 05/29/2012 05:02 AM, BartC wrote:
    > "Ike Naar" <> wrote in message
    > news:...
    >> On 2012-05-29, Lox <> wrote:

    ....
    >>> void test(void)
    >>> {
    >>> uint8_t a;
    >>> uint32_t i;
    >>>
    >>> a = 10;
    >>>
    >>> for(i = 0; i < (a + 1); i++)
    >>> {
    >>>
    >>> }
    >>> }

    >>
    >> Integer promotions.
    >> In i < (a + 1), a is promoted to an int because, apparently on your
    >> implementation, int can represent all values of type uint8_t.

    >
    > So all the discussion in the recent thread ("condition true or false? ...")
    > about mixed arithmetic being unsigned, isn't always true?


    A lot of things were said in that discussion by people with varying
    levels of understanding of the language. What actually happens depends
    upon the usual arithmetic conversions, which start with the integer
    promotions. The assertion some participants made that "mixed arithmetic
    is unsigned" was, at best, a simplification that becomes false under two
    circumstances:

    1. If all possible values of the unsigned type can be represented as an
    'int', the unsigned value is promoted to an 'int'. The same rule applies
    to the signed type. The expression is evaluated using whichever promoted
    type has the higher integer conversion rank.

    2. If the expression still has mixed signedness after the integer
    promotions, the following rule applies to the promoted types of the
    operands. If the unsigned type and has an integer conversion rank less
    than that of the signed type, and all values of the unsigned type can be
    represented in the signed type, then the expression is evaluated using
    the signed type.

    > (Yes I've now read 6.3.1.8. But why would C care more about preserving
    > possible negative values of a wider int, than the negative values of a
    > narrower int? The mixed arithmetic rule could have been more consistent.)


    One key concept in C is that 'int' and 'unsigned int' were chosen by the
    implementation to be the natural type for ordinary integer arithmetic.
    Therefore, C requires promotion to one of those two types, if the result
    is value preserving, before anything other aspect of the usual
    arithmetic conversions are applied. It is consistent application of that
    rule that produces the result that you consider inconsistent.
    --
    James Kuyper
     
    James Kuyper, May 29, 2012
    #8
  9. Lox

    Ike Naar Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 2012-05-29, Lox <> wrote:
    > I also tested the integer promotion in the following examples.
    >
    > uint32_t x;
    > uint8_t y;
    >
    > x = 255;
    > y = x + UINT8_C(1);
    >
    > y is 256 and not 255 as one would think.


    Two questions:
    - why would one think that y would be 255 ?
    - uint8_t can hold the values [0,255], so how could y ever be 256 ?

    > but in:
    >
    > uint32_t x;
    > uint8_t y;
    >
    > x = 255;
    > y = (u8_t)(x + UINT8_C(1));
    >
    > y is 255


    Very unlikely. How did you come to that conclusion?
     
    Ike Naar, May 29, 2012
    #9
  10. Lox

    Lox Guest

    Sorry, two typos (wrote to fast). :p

    uint32_t x;
    uint8_t y;

    x = 255;
    y = x + UINT8_C(1);

    y is 256 and not 0 as one would think (if assuming 8 bit
    calculations).

    but in:

    uint32_t x;
    uint8_t y;

    x = 255;
    y = (u8_t)(x + UINT8_C(1));

    y is 0

    :)
     
    Lox, May 31, 2012
    #10
  11. Lox

    Ike Naar Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 2012-05-31, Lox <> wrote:
    > Sorry, two typos (wrote to fast). :p
    >
    > uint32_t x;
    > uint8_t y;
    >
    > x = 255;
    > y = x + UINT8_C(1);
    >
    > y is 256 and not 0 as one would think (if assuming 8 bit
    > calculations).


    Again, y can only hold values from 0 to 255 inclusive,
    so it cannot be 256. How did you come to that conclusion?
    Can you show the code?

    Here's code that suggests y equals 0:

    #include <stdint.h>
    #include <assert.h>
    int main(void)
    {
    uint32_t x = 255;
    uint8_t y = x + UINT8_C(1);
    assert(y == 0);
    return 0;
    }

    > but in:
    >
    > uint32_t x;
    > uint8_t y;
    >
    > x = 255;
    > y = (u8_t)(x + UINT8_C(1));


    What is (u8_t) ? Did you mean (uint8_t) ?

    > y is 0


    Indeed.
     
    Ike Naar, May 31, 2012
    #11
  12. Lox

    Joe Pfeiffer Guest

    Ike Naar <> writes:

    > On 2012-05-31, Lox <> wrote:
    >> Sorry, two typos (wrote to fast). :p
    >>
    >> uint32_t x;
    >> uint8_t y;
    >>
    >> x = 255;
    >> y = x + UINT8_C(1);
    >>
    >> y is 256 and not 0 as one would think (if assuming 8 bit
    >> calculations).

    >
    > Again, y can only hold values from 0 to 255 inclusive,
    > so it cannot be 256. How did you come to that conclusion?
    > Can you show the code?


    If I'm reading the standard correctly, an unsigned char is large
    enough to hold values from 0 to 255 (actually "any member of the basic
    execution character set"). It doesn't say that it can't be larger than
    that.

    > Here's code that suggests y equals 0:
    >
    > #include <stdint.h>
    > #include <assert.h>
    > int main(void)
    > {
    > uint32_t x = 255;
    > uint8_t y = x + UINT8_C(1);
    > assert(y == 0);
    > return 0;
    > }


    I tried a similar experiment, and also got 0 (as you and I both
    expected!). I wouldn't be at all surprised to learn that a processor
    with a character set that didn't handle 8 bit quantities well, or indeed
    some other compiler than gcc even on Intel, was able to store a value
    greater than 255 in an unsigned char.
     
    Joe Pfeiffer, May 31, 2012
    #12
  13. Lox

    James Kuyper Guest

    Re: Why, warning: comparison between signed and unsigned integerexpressions?

    On 05/31/2012 01:09 PM, Joe Pfeiffer wrote:
    > Ike Naar <> writes:
    >
    >> On 2012-05-31, Lox <> wrote:
    >>> Sorry, two typos (wrote to fast). :p
    >>>
    >>> uint32_t x;
    >>> uint8_t y;
    >>>
    >>> x = 255;
    >>> y = x + UINT8_C(1);
    >>>
    >>> y is 256 and not 0 as one would think (if assuming 8 bit
    >>> calculations).

    >>
    >> Again, y can only hold values from 0 to 255 inclusive,
    >> so it cannot be 256. How did you come to that conclusion?
    >> Can you show the code?

    >
    > If I'm reading the standard correctly, an unsigned char is large
    > enough to hold values from 0 to 255 (actually "any member of the basic
    > execution character set"). ...


    Actually, the key requirement is that UCHAR_MAX >= 255 (5.2.4.2.1p1).

    > ... It doesn't say that it can't be larger than
    > that.


    While that's all perfectly true, it's not relevant. The type used in
    this example was uint8_t, not char. uint8_t is required by the standard
    to have exactly 8 values bits, no more, and no less; and no padding bits
    (7.20.1.1p2). On any implementation where uint8_t can be implemented,
    it's likely (but not required) to be the same type as unsigned char.
    However, uint8_t is an optional type, for precisely the reason that it
    cannot be implemented as specified on any implementation where CHAR_BIT > 8.
     
    James Kuyper, May 31, 2012
    #13
  14. Lox

    Joe Pfeiffer Guest

    James Kuyper <> writes:

    > On 05/31/2012 01:09 PM, Joe Pfeiffer wrote:
    >> Ike Naar <> writes:
    >>
    >>> On 2012-05-31, Lox <> wrote:
    >>>> Sorry, two typos (wrote to fast). :p
    >>>>
    >>>> uint32_t x;
    >>>> uint8_t y;
    >>>>
    >>>> x = 255;
    >>>> y = x + UINT8_C(1);
    >>>>
    >>>> y is 256 and not 0 as one would think (if assuming 8 bit
    >>>> calculations).
    >>>
    >>> Again, y can only hold values from 0 to 255 inclusive,
    >>> so it cannot be 256. How did you come to that conclusion?
    >>> Can you show the code?

    >>
    >> If I'm reading the standard correctly, an unsigned char is large
    >> enough to hold values from 0 to 255 (actually "any member of the basic
    >> execution character set"). ...

    >
    > Actually, the key requirement is that UCHAR_MAX >= 255 (5.2.4.2.1p1).
    >
    >> ... It doesn't say that it can't be larger than
    >> that.

    >
    > While that's all perfectly true, it's not relevant. The type used in
    > this example was uint8_t, not char. uint8_t is required by the standard
    > to have exactly 8 values bits, no more, and no less; and no padding bits
    > (7.20.1.1p2). On any implementation where uint8_t can be implemented,
    > it's likely (but not required) to be the same type as unsigned char.
    > However, uint8_t is an optional type, for precisely the reason that it
    > cannot be implemented as specified on any implementation where CHAR_BIT > 8.


    Ah. I was looking for the string uint8_t in the standard and not
    finding it... You are correct.
     
    Joe Pfeiffer, May 31, 2012
    #14
    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. John Buckley

    comparison between signed and unsigned

    John Buckley, Oct 23, 2003, in forum: C Programming
    Replies:
    2
    Views:
    479
    Dan Pop
    Oct 24, 2003
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,988
    Smokey Grindel
    Dec 2, 2006
  3. Alex
    Replies:
    3
    Views:
    646
    Michael Mair
    Apr 26, 2006
  4. Gary Wessle
    Replies:
    4
    Views:
    635
    Ian Collins
    Jul 29, 2006
  5. Replies:
    6
    Views:
    387
    Army1987
    Sep 21, 2007
Loading...

Share This Page