Radoslaw Krasimirow
Radoslaw Krasimirow

Reputation: 1873

need help understanding ususual arithmetic conversions

This line I found in c11/N1570 6.3.1.8 - Usual arithmetic conversions:

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.

Then I did test like this

uint8_t ui8 = 0xFF;
int16_t i16 = 255;

if(i16 == ui8)
    printf("%#.8X\n", i16);

According to my (obviously) wrong deduction herein i16 == ui8, ui8 is implicitly converted to int8_t (according to the rule quoted above). After the conversion ui8 equals -1 so the if must "expand" to something like this;

if(i16 == (int8_t)ui8)

or

if(255 == -1)

which is not true. What bothers me is that after I ran the code the condition appeared to be true. Can you please help me to understand what am I missing in the quote above?

Upvotes: 0

Views: 84

Answers (2)

David C. Rankin
David C. Rankin

Reputation: 84521

You have to understand what is occurring here. When you declare:

uint8_t ui8 = 0xFF;
int16_t i16 = 255;

both ui8 and i16 have their first 8-bits set. In both cases, their value is 255. You can easily check this is the maximum for an unsigned 8-bit value:

char - signed       :        -128  to  127
char - unsigned     :           0  to  255

The problem arises here:

if(i16 == (int8_t)ui8)

When ui8 is promoted to int16_t, sign-extension occurs (which extends the left-most bit in ui8 duplicating it across bits 8-15 during the conversion. This leaves you with an int16_t representation of ui8 being a negative value which causes the above comparison to succeed, (but for the wrong reason). You must be very careful when mixing signed/unsigned values for this reason.

Upvotes: 3

verbose
verbose

Reputation: 7917

The type of the signed operand i16 in this case is int16t. When the comparison is done, it is between an unsigned and a signed value. Since the signed type int16t is capable of holding all the possible values of uint8t, the uint8t value can be converted to int16t. So FF is implicitly converted to 255, not to -1. This makes the condition true.

From Harbison and Steele's C: A Reference Manual 5e, p. 190:

the general rule for converting from one integer type to another is that the mathematical value of the result should equal the original mathematical value if that is possible. For example, if an unsigned integer has the value 15 and this value is to be converted to a signed type, the resulting signed value should be 15 also.

Upvotes: 3

Related Questions