1

Consider the following code:

signed  a = -1;
unsigned b = UINT_MAX;
printf("%d\n", a==b);
signed char c = -1;
unsigned char d = UCHAR_MAX;
printf("%d\n", c==d);

The result will be:

1
0
  1. Why is "==" for char is based on the actual value, and for an int is based on the bit representation?

  1. Consider this code:
signed char a = -1;
unsigned char b = 255;
printf(“%d\n”, a);
printf(“%d\n”, b);
signed  c = -1;
unsigned d = UINT_MAX;
printf(“%d\n”, c);
printf(“%d\n”, d);

The result will be:

-1
255
-1
-1

%d represents char based on actual value but not int

3

3 Answers 3

2

The usual arithmetic conversions will be applied to both the operands of most binary operations on numbers to convert them to a common numeric type before the operation is performed.

The first step of the usual arithmetic conversions is to apply the integer promotions to the numeric operands. This only affects operands whose integer rank is less than that of the type int (and unsigned int). So it will affect the operand types _Bool, char, signed char, unsigned char, short, and unsigned short, and also bit-fields of various widths. The integer promotions do not change the numeric value of the operand, only the type. If int can represent all values of the original lower rank type (as restricted by the width for a bit-field), then the lower rank value will be converted to int, otherwise the lower rank value will be converted to unsigned int:

  • The comparison (signed char)-1 == (unsigned char)255 will be converted to (int)-1 == (int)255 by the integer promotion rules.
  • The comparison (signed int)-1 == (unsigned int)UINT_MAX will be left unchanged by the integer promotion rules.

The second step of the usual arithmetic conversions is to convert the promoted operands to a common numeric type. When one operand has type int and the other operand has type unsigned int, the operand of type int will be converted to unsigned int, which will change negative values to large, positive values:

  • The comparison (signed char)-1 == (unsigned char)255 will be converted to (int)-1 == (int)255 by integer promotion and will remain as (int)-1 == (int)255 after the remaining usual arithmetic conversions. The result of the comparison is 0.
  • The comparison (signed int)-1 == (unsigned int)UINT_MAX will be left unchanged by integer promotion and will be converted to (unsigned int)UINT_MAX == (unsigned int)UINT_MAX by the remaining arithmetic conversions (since (unsigned int)-1 is the same as (unsigned int)UINT_MAX). The result of the comparison is 1.

The second part of OP's question has undefined behavior here:

unsigned d = UINT_MAX;
printf(“%d\n”, d);

The printf format specifier %d expects an argument of type int, but an argument of type unsigned int has been supplied, resulting in UB. However, assuming the compiler passes int arguments in the same way as unsigned int arguments, what is likely to happen is that printf will re-interpret the binary representation of the unsigned int value as an int value. Assuming int has a 2's complement representation with no padding bits, the binary representations of (int)-1 and (unsigned int)UINT_MAX will be identical, so printf will output -1 since it is expecting an int. (Reminder: this is undefined behavior.)

The variadic arguments of the printf call will have the default argument promotions applied. Arguments of type float will be converted to double, and the integer promotions will be applied to arguments of integer type, so:

  • (signed char)-1 will be converted to (int)-1
  • (unsigned char)255 will be converted to (int)255
  • (int)-1 will remain unchanged
  • (unsigned int)UINT_MAX will remain unchanged, and will result in undefined behavior because printf is expecting an int.
Sign up to request clarification or add additional context in comments.

7 Comments

you forgot the second part %d
@Elicon OP did not ask a question about the second part. :-)
@Elicon OP = "Original Poster". I just realized that is you. :-)
RE "(unsigned int)UINT_MAX will remain unchanged." wrong (unsigned int)UINT_MAX will be converted to (int) UINT_MAX
@Elicon No, (unsigned int)UINT_MAX will not be converted. An implementation of printf may re-interpret that unsigned int value as an int but the C standard does not define what printf should do, i.e. it is UB.
|
2

It is implementation-defined (i.e. up to the compiler) if char is signed or unsigned. Also, whenever a type smaller than int is used in an arithmetic expression, it will be promoted to an int.

And since the promotion will do sign-extension, the signed char will be promoted to the value -1, but an unsigned will be promoted to the value 255.

This is a major reason all character reading functions return an int, so they can be directly compared to the int value EOF.


Because of the implementation-defined nature of char, there are actual three different types for char, unlike all other integer types:

  1. signed char
  2. unsigned char
  3. char.

When a char is promoted to an int, the value needs to stay the same. So -1 is still -1, and 255 is still 255.

3 Comments

It would help if you could give a binary demonstration of the variables after the promotion. char and ints. what with %d
@Elicon, Promotion is not a binary thing. It's a type change with no change in value. char 3 promotes to int 3. char -4 promotes to int -4.
You forgot to mention the usual arithmetic conversions, which is important when comparing signed int values with unsigned int values, so the answer does not currently answer all of the question.
-4

The behavior of comparisons between signed and unsigned types involves type promotion and conversion rules in C. When a signed value is compared with an unsigned value, the signed value is converted to unsigned, which can lead to unexpected results. The %d format specifier prints the actual value for signed types, while for unsigned types, it represents their value as a positive integer.

If you meant to say that the output for d should be 4294967295, that would be correct. The output of printf("%d\n", d); should reflect the unsigned representation, which is not -1.

4 Comments

In unsigned d = UINT_MAX; printf("%d\n", d); there is undefined behavior. There is no should. Such a program is allowed to print or do anything.
Re “When a signed value is compared with an unsigned value, the signed value is converted to unsigned”: This is wrong in two ways. First, what conversions are applied in the usual arithmetic conversions is based on types, not values. If an int value of −3 is compared with a int value of 4, there is no conversion, even though one value is signed and the other is not, because the types are the same. Second, rank must be considered. Given a value in a signed type of high rank and a value in an unsigned type of low rank, the latter will be converted to the signed type.
Re “The %d format specifier … for unsigned types, it represents their value as a positive integer”: Up to C 2018, the behavior when an unsigned int was passed for %d was not defined, per C 2018 7.21.6.1 9: “… If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.” In the case where the printf call was actually performed as written (the compiler did not observe the problem and reject the code, and optimization did not affect it), a common behavior was to interpret the bytes of the unsigned int as an int
… This would result in unsigned int values that were representable as int being printed as those values and unrepresentable values being printed as negative numbers according to their two’s complement interpretation (or, in now esoteric C implementations, one’s complement or sign-and-magnitude). So printf("%d\n", d); with d = 4,294,967,295, would print “-1”, not “4294967295”. C 2024 makes the behavior defined when the unsigned int value is representable in int but leaves it undefined for values not representable in int.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.