tags:

views:

672

answers:

6

In the code block below what's the impicit conversion that takes place in the if statement for 7? I would have though it would end up being (0x98 <= 0x07) but that's not what happens as the condition evaluates to true and DoMyStuff gets called.

char minstogo = 0x98;
if(minstogo <= 7) {
   DoMyStuff();
}
+5  A: 

What's likely happening here is that char is a signed value and 0x98 is hence registering as a negative number. Hence it is less than 7

Also in this scenario, 7 will under go no conversion. Instead the char will be widened to the same integral type as 7 and then a comparison will be done.

JaredPar
A: 

Using your compiler with its current settings, char is a signed type: and because the high order bit (0x80) of its value is set, that value is negative. When minstogo is widened, that negative sign is preserved (via sign-extension), and so minstogo is widened to a negative integer (e.g. 0xFF98), which is less than 7.

ChrisW
It's got an implementation defined sign. Sometimes it's signed (on some hosts), sometimes (on other hosts) it's not.
Johannes Schaub - litb
Whether char is signed or unsigned varies by platform, compiler, and configuration; for example, the PowerPC ABI suggests that char is unsigned, and GCC takes `-fsigned-char`/`-funsigned-char` switches to override the platform defaults. Portable code should not rely on the (un)signedness of char.
ephemient
The OP's compiler is treating his char as a signed type.
ChrisW
Using MSVC it's signed by default, with a compiler option to make it unsigned.
ChrisW
On x86, all compilers follow the ABI's suggestion for signed chars. I am not arguing that this is the OP's problem; in fact, the question makes it fairly obvious that it is. I am arguing with your overarching statement that "char is a signed type" -- this needs to be qualified with "on some systems" or "in this case", because it is very much false on many existing systems in active use today.
ephemient
Ok. "Using your compiler with its current settings, char is a signed type".
ChrisW
The C standard doesn't actually require two's complement signed integers, so 0x98 could be any of a number of implementation defined values when forced into a signed char.... not that any of the others will often be caught in the wild, though.
RBerteig
@RBerteig That's true but I was trying to answer the OP's question ("what's the impicit conversion that takes place?"), about what's happening on his machine, without loading on a bunch of extra theory about other behaviours on other machines.
ChrisW
A: 

0x98 is 152.

Since you've declared a "char", and not an "unsigned char", you're trying to assign 152 to a type that has a range of -128 - 127.

This is going to overflow, and give you a negative number, which will be < 7 (0x07).

Reed Copsey
+1  A: 

With chars being represented as an eight-bit byte, setting minstogo to 0x98 is a binary value of 10011000. The sign bit is set, it's a negative integer value. You probably want an unsigned char in order for the test to evaluate false.

brlcad
+1  A: 

It will evaluate the same as 0x98 <= 7 unless the platform's char type defaults to signed and CHAR_BIT is 8. In that case, the value of minstogo will be negative and minstogo <= 7 will be true.

Dingo
+9  A: 

Whenever you have a binary operator (one of + - * / % << >> & | ^ == != < <= > >=) between two integral operands of different types, the two types are converted to a common type before the operation is performed. The rules for deciding the converted-to type are (from section 6.3.1.8 of the C99 standard):

If both operands have the same type, then no further conversions are required.

Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.

Otherwise, if the operand that has unsigned integer type has rank greater or equal to the rank of the type of the other operand, then the operand with signed integer type is converted to the type of the operand with unsigned integer type.

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.

Otherwise, both operands are converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

In this case, char could be either a signed or unsigned integer type -- its signedness is implementation-defined. Fortunately, though, an int can represent all possible values of a char, whether or not char is signed, assuming you're on a system where chars are 8 bits and ints are at least 16 bits.

If char is signed, then the second paragraph above applies, so both operands are converted to int (the type with higher rank; rank is defined in a somewhat complicated manner, but it's essentially equivalent to the bit size of the type). Since 0x98, as a signed char, is negative, it's converted to the integer -104, which is then less than 7.

If instead char is unsigned, then the fourth paragraph applies instead. The unsigned char would be converted to 152 as an int, which is greater than 7.

Do not ever rely on chars being signed or unsigned. If you need 8-bit integers of a certain signedness, explicitly use signed char or unsigned char, or use the C99 types int8_t and uint8_t, defined int <stdint.h>.

It's very easy to get bitten by subtle bugs caused by the integer promotion rules. I strongly advise you to always compile with -Wall with gcc, which will warn you about comparisons between signed and unsigned integers, which are frequently a cause of bugs.

Adam Rosenfield