unsigned char + constant

B

barcaroller

Does anyone know why the gcc compiler complains about the second 'if'
condition:


unsigned char x = 0;
size_t y = 0;

// okay; no compiler warning
if (x < y)
...

// compiler warning: comparing signed and unsigned values
if ((x+1) < y)
...


My guess is that (x+1) somehow becomes an 'int', but that would not be
intuitive and could have undesirable consequences.
 
S

santosh

barcaroller said:
Does anyone know why the gcc compiler complains about the second
'if' condition:


unsigned char x = 0;
size_t y = 0;

// okay; no compiler warning
if (x < y)
...

// compiler warning: comparing signed and unsigned values
if ((x+1) < y)
...


My guess is that (x+1) somehow becomes an 'int', but that would not
be intuitive and could have undesirable consequences.

You're basically correct. Quoting a relevant section from the
standard:

----------
6.3.1.8 (1)

Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, then the operand with unsigned integer type is
converted to the type of the operand with signed integer type.
----------

So (x+1) yields a value of type int since the literal 1 has a higher
conversion rank than x, on your compiler, which you then compare with
an unsigned value. This is a standard warning from gcc. You can use
the switches -Wno-sign-conversion or -Wno-sign-compare to disable
these specific warnings. Or you can cast one of the objects in the
expression to get the type of conversions you desire.
 
M

Mark

santosh said:
// compiler warning: comparing signed and unsigned values
if ((x+1) < y)
...
[snip]
So (x+1) yields a value of type int since the literal 1 has a higher
conversion rank than x, on your compiler, which you then compare with
an unsigned value. This is a standard warning from gcc. You can use
the switches -Wno-sign-conversion or -Wno-sign-compare to disable
these specific warnings. Or you can cast one of the objects in the
expression to get the type of conversions you desire.

Perhaps (x + 1u) would be better.
 
P

Peter Nilsson

barcaroller said:
Does anyone know why the gcc compiler complains about the
second 'if' condition:

    unsigned char x = 0;
    size_t        y = 0;

    // okay; no compiler warning
    if (x < y)
        ...

    // compiler warning: comparing signed and unsigned values
    if ((x+1) < y)
        ...

My guess is that (x+1) somehow becomes an 'int',

As does x in the first case.

Well, actually, it depends on the implementation. If INT_MAX
can hold the range 0..UCHAR_MAX, then x will be promoted to
a (signed) int, otherwise it will be promoted to an unsigned
int for comparison purposes. It may be subject to further
'arithmetic' conversion depending on size_t.

I dare say that gcc is checking if the two operands are
unsigned (prior to integral promotion.) If so, then the
comparison is fine. If not, then the comparison may or
may not be fine, hence the warning.
but that would not be intuitive and could have undesirable
consequences.

Intuitive or not, it is what the C language requires.

However, you can rest assured that any promotion is value
preserving for non-negative values. That said, x + 1, is
theoretically problematic and you should check your code
for errant behaviour on bizarre implementations, should
you wish the code to be maximally portable.

If you want the mathematical condition to hold, then the
second clause can be written portably as...

if (y != 0 && x < y - 1)

The original code can fail in the case where y is non-zero
and x has the value UCHAR_MAX, and x promotes to unsigned
int. In that case x + 1 will yield 0 (as an unsigned int)
which of course compares less than a positive value, even
if y has a positive value lower UCHAR_MAX.
 
S

santosh

Branimir Maksimovic said:
Well OP wasn't specific. Which version of gcc (and platform), with
complete source code that gives warning.
I've tried gcc 4.4 (and comeau online), but cannot reproduce
warning.

I don't clearly remember, but I think you would need the -Wall and
possibly -Wextra switches to make gcc warn about this.
 
E

Eric Sosman

Mark said:
santosh said:
// compiler warning: comparing signed and unsigned values
if ((x+1) < y)
...
[snip]
So (x+1) yields a value of type int since the literal 1 has a higher
conversion rank than x, on your compiler, which you then compare with
an unsigned value. This is a standard warning from gcc. You can use
the switches -Wno-sign-conversion or -Wno-sign-compare to disable
these specific warnings. Or you can cast one of the objects in the
expression to get the type of conversions you desire.

Perhaps (x + 1u) would be better.
Well actually, I would leave this warning, as maintainers would notice
that and correct possible bug, as x+1<y is meaningless when
x == UCHAR_MAX, anyway.
x+1<=UCHAR_MAX would be completely different thing.

(Context: x is unsigned char, y is size_t.)

There's nothing special about x==UCHAR_MAX that would
somehow render x+1<y meaningless. On many platforms (including
the one the O.P. uses), x+1 would just be 256, a perfectly
good int, which would then be converted to size_t and compared
to y.

It's of course possible that the meaning of the expression
is not what the O.P. intended -- but that's true of any construct,
even printf("Hello, world!\n").
 
P

Peter Nilsson

Eric Sosman said:
     (Context: x is unsigned char, y is size_t.)

     There's nothing special about x==UCHAR_MAX that would
somehow render x+1<y meaningless.

Except for the pathological case where INT_MAX == UCHAR_MAX.

Also, if UCHAR_MAX == UINT_MAX then x + 1 yields 0 and compares
less than _any_ non zero y. Of course, that case isn't meanless
per se, but it's unlikely to be the intended effect of the
condition.
 
P

Peter Nilsson

Branimir Maksimovic said:
Well it's not pathological case, because I remember someone of
regulars here mentioned that some DSPs have bad habit that all
types are 32 bits...

Why is that bad? In any case, it's not the pathological case.
On such implementations INT_MAX < UCHAR_MAX.
 
L

lovecreatesbeauty

As does x in the first case.

Well, actually, it depends on the implementation. If INT_MAX
can hold the range 0..UCHAR_MAX, then x will be promoted to
a (signed) int, otherwise it will be promoted to an unsigned
int for comparison purposes. It may be subject to further
'arithmetic' conversion depending on size_t.

I dare say that gcc is checking if the two operands are
unsigned (prior to integral promotion.) If so, then the
comparison is fine. If not, then the comparison may or
may not be fine, hence the warning.


Intuitive or not, it is what the C language requires.

However, you can rest assured that any promotion is value
preserving for non-negative values. That said, x + 1, is
theoretically problematic and you should check your code
for errant behaviour on bizarre implementations, should
you wish the code to be maximally portable.

If you want the mathematical condition to hold, then the
second clause can be written portably as...

  if (y != 0 && x < y - 1)

The original code can fail in the case where y is non-zero
and x has the value UCHAR_MAX, and x promotes to unsigned
int. In that case x + 1 will yield 0 (as an unsigned int)
which of course compares less than a positive value, even
if y has a positive value lower UCHAR_MAX.

Peter, thanks for your beautiful explanation. But I have some doubt. I
think Op's code doesn't fail. OP's code will fail when x types of
unsigned int and y types of long. Integral expression defaults to int,
so x+1 with x equals to UCHAR_MAX won't yields 0, but value of
UCHAR_MAX+1 types of int.
 
E

Eric Sosman

Except for the pathological case where INT_MAX == UCHAR_MAX.

... implying at least fourteen padding bits in an int, which
as far as I know only happens on the DeathStation, and only for
programs compiled in the dark of the Moon.
Also, if UCHAR_MAX == UINT_MAX then x + 1 yields 0 and compares
less than _any_ non zero y. Of course, that case isn't meanless
per se, but it's unlikely to be the intended effect of the
condition.

This situation seems a good deal more likely. DSP's where
sizeof(int)==1 have been mentioned elsethread.
 
R

Richard Bos

Peter Nilsson said:
Why is that bad? In any case, it's not the pathological case.
On such implementations INT_MAX < UCHAR_MAX.

Not allowed. 6.2.5#8 in C99:

# 8 For any two integer types with the same signedness and different
# integer conversion rank (see 6.3.1.1), the range of values of the
# type with smaller integer conversion rank is a subrange of the
# values of the other type.

(And yes, 6.3.1.1 does say that "the rank of int ... shall be greater
than ... the rank of signed char".)

In C89, it's even simpler; in 6.1.2.5, it says:

# There are four signed integer types, designated as signed char,
# short int, int, and long int.
# ...
# In the list of signed integer types above, the range of values of each
# type is a subrange of the values of the next type in the list.

Richard
 
P

Peter Nilsson

Not allowed. 6.2.5#8 in C99:

Yes it is.
# 8 For any two integer types with the same signedness and
^^^^^^^^^^^^^^^
# different integer conversion rank (see 6.3.1.1), the range
# of values of the type with smaller integer conversion rank
# is a subrange of the values of the other type.

There are many implementations today where INT_MAX < USHRT_MAX.
 
P

Peter Nilsson

...I think Op's code doesn't fail. OP's code will fail when
x types of unsigned int and y types of long. Integral
expression defaults to int,

No, promotion to unsigned int is possible if int cannot
represent the values of an expression.
so x+1 with x equals to UCHAR_MAX won't yields 0,

It can if INT_MAX < UCHAR_MAX, e.g. embedded systems
(freestanding implementations) where integer types
are all the same size, say 32 or 64-bit.
but value of UCHAR_MAX+1 types of int.

On most hosted implementations, yes.
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top