Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

1,402 views
Skip to first unread message

Lox

unread,
May 29, 2012, 2:15:41 AM5/29/12
to
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?

bartek szurgot

unread,
May 29, 2012, 3:21:58 AM5/29/12
to
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] and clang-3.0, but id say that a+1 is uint8_t+int, that
gives int, thus signed. try a+1u instead.


> 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++)
> {
>
> }
> }

now you're using explicit casting, that is forcing a compiler to write
result as the uint32_t, i.e. unsigned type, so there is no warning.

--
pozdrawiam serdecznie / best regards,
bartek szurgot
/* http://www.baszerr.eu */

Ike Naar

unread,
May 29, 2012, 3:32:08 AM5/29/12
to
On 2012-05-29, bartek szurgot <ba...@no.spam> 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

unread,
May 29, 2012, 3:56:01 AM5/29/12
to
On 2012-05-29, Lox <skolpo...@yahoo.se> 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.

io_x

unread,
May 29, 2012, 4:20:55 AM5/29/12
to

"Lox" <skolpo...@yahoo.se> ha scritto nel messaggio
news:5fd3475c-d5bb-425f...@6g2000vbv.googlegroups.com...
> 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++)

because i not understand well eglish possible i fail...
but someone say some days ago it has to be (a+1) promoted to int from u8
that is signed... so the warning


Lox

unread,
May 29, 2012, 5:00:35 AM5/29/12
to
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.

BartC

unread,
May 29, 2012, 5:02:18 AM5/29/12
to


"Ike Naar" <i...@sverige.freeshell.org> wrote in message
news:slrn3vfsjs9...@sverige.freeshell.org...
> On 2012-05-29, Lox <skolpo...@yahoo.se> 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

Lox

unread,
May 29, 2012, 5:08:36 AM5/29/12
to
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

:-)

James Kuyper

unread,
May 29, 2012, 6:28:41 AM5/29/12
to
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

unread,
May 29, 2012, 7:00:53 AM5/29/12
to
On 05/29/2012 05:02 AM, BartC wrote:
> "Ike Naar" <i...@sverige.freeshell.org> wrote in message
> news:slrn3vfsjs9...@sverige.freeshell.org...
>> On 2012-05-29, Lox <skolpo...@yahoo.se> 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

David T. Ashley

unread,
May 29, 2012, 7:57:23 AM5/29/12
to
On Tue, 29 May 2012 07:00:53 -0400, James Kuyper
<james...@verizon.net> wrote:

>It is consistent application of that
>rule that produces the result that you consider inconsistent.

That's quite a quote.

DTA

Ike Naar

unread,
May 29, 2012, 8:57:43 AM5/29/12
to
On 2012-05-29, Lox <skolpo...@yahoo.se> 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?

Lox

unread,
May 31, 2012, 2:44:03 AM5/31/12
to
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

:-)

Ike Naar

unread,
May 31, 2012, 3:13:03 AM5/31/12
to
On 2012-05-31, Lox <skolpo...@yahoo.se> 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.

Joe Pfeiffer

unread,
May 31, 2012, 1:09:54 PM5/31/12
to
Ike Naar <i...@iceland.freeshell.org> writes:

> On 2012-05-31, Lox <skolpo...@yahoo.se> 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.

James Kuyper

unread,
May 31, 2012, 1:22:52 PM5/31/12
to
On 05/31/2012 01:09 PM, Joe Pfeiffer wrote:
> Ike Naar <i...@iceland.freeshell.org> writes:
>
>> On 2012-05-31, Lox <skolpo...@yahoo.se> 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.

Joe Pfeiffer

unread,
May 31, 2012, 2:11:40 PM5/31/12
to
Ah. I was looking for the string uint8_t in the standard and not
finding it... You are correct.
0 new messages