#include<stdio.h>
int main()
{
unsigned int a=6;
int b=-20;
(a+b>6)?puts(">6"):puts("<=6");
return 0;
}
The above code outputs >6. But I got a doubt. b=-20 will hold a negative value (-18)
after doing the 2's complement as it's a signed integer. So it should output <=6 but its
giving an output as >6.
From the C99 standard, section 6.3.1.8 ("Usual arithmetic conversions"):
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.
Basically, in the case of your example code, unsigned int and int have the same rank, so it's equivalent to:
(a + (unsigned int)b > 6)
To fix it, you need to explicitly cast in the other direction, i.e.:
((int)a + b > 6)
The answer is to be found in section "6.3.1.8 Usual arithmetic conversions" of the C99 standard, which favors the unsigned type when a signed type and an unsigned one are passed to a binary operator (the reality is much more subtle than that).
See this blog post for another example of working through the rules in 6.3.1.8.
You are mixing signed and unsigned integers in your code. That is a bad thing. Try the following snippet:
int main()
{
unsigned int a = 0;
int b=-20;
printf("(a + b) = %f", (a + b));
return 0;
}
Don't mix signed and unsigned integers because the compiler will do a silent conversion just when you don't want it to.
Related
I'm trying to subtract two unsigned ints and compare the result to a signed int (or a literal). When using unsigned int types the behavior is as expected. When using uint16_t (from stdint.h) types the behavior is not what I would expect. The comparison was done using gcc 4.5.
Given the following code:
unsigned int a;
unsigned int b;
a = 5;
b = 20;
printf("%u\n", (a-b) < 10);
The output is 0, which is what I expected. Both a and b are unsigned, and b is larger than a, so the result is a large unsigned number which is greater than 10. Now if I change a and b to type uint16_t:
uint16_t a;
uint16_t b;
a = 5;
b = 20;
printf("%u\n", (a-b) < 10);
The output is 1. Why is this? Is the result of subtraction between two uint16_t types stored in an int in gcc? If I change the 10 to 10U the output is again 0, which seems to support this (if the subtraction result is stored as an int and the comparison is made against an unsigned int than the subtraction results will be converted to an unsigned int).
Because calculations are not done with types below int / unsigned int (char, short, unsigned short etc; but not long, unsigned long etc), but they are first promoted to one of int or unsigned int. "uint16_t" is possibly "unsigned short" on your implementation, which is promoted to "int" on your implementation. So the result of that calculation then is "-15", which is smaller than 10.
On older implementations that calculate with 16bit, "int" may not be able to represent all values of "unsigned short" because both have the same bitwidth. Such implementations must promote "unsigned short" to "unsigned int". On such implementations, your comparison results in "0".
Before both the - and < operations are performed, a set of conversions called the usual arithmetic conversions are applied to convert the operands to a common type. As part of this process, the integer promotions are applied, which promote types narrower than int or unsigned int to one of those two types.
In the first case, the types of a and b are unsigned int, so no change of types occurs due to the - operator - the result is an unsigned int with the large positive value UINT_MAX - 14. Then, because int and unsigned int have the same rank, the value 10 with type int is converted to unsigned int, and the comparison is then performed resulting in the value 0.
In the second case, it is apparent that on your implementation the type int can hold all the values of the type uint16_t. This means that when the integer promotions are applied, the values of a and b are promoted to type int. The subtraction is performed, resulting in the value -15 with type int. Both operands to the < are already int, so no conversions are performed; the result of the < is 1.
When you use a 10U in the latter case, the result of a - b is still -15 with type int. Now, however, the usual arithmetic conversions cause this value to be converted to unsigned int (just as the 10 was in the first example), which results in the value UINT_MAX - 14; the result of the < is 0.
[...] Otherwise, the integer promotions are performed on both operands. (6.3.1.8)
When uin16_t is a sub-range of int, (a-b) < 10 is performed using int math.
Use an unsigned constant to gently nudge the left side to unsigned math.
// printf("%u\n", (a-b) < 10);
printf("%d\n", (0u + a - b) < 10); // Using %d as the result of a compare is int.
// or to quiet some picky warnings
printf("%d\n", (0u + a - b) < 10u);
(a - b) < 10u also works with this simple code, yet the idea I am suggesting to to perform both sides as unsigned math as that may be needed with more complex code.
I am trying to work out how unsigned overflow works with subtraction, so I wrote the following test to try it out:
#include<stdio.h>
#include<stdlib.h>
unsigned char minWrap(unsigned char a, unsigned char b) {
return a > b ? a - b : a + (0xff - b) + 1;
}
int main(int argc, char *argv[]) {
unsigned char a = 0x01, b = 0xff;
unsigned char c = a - b;
printf("0x%02x 0x%02x 0x%02x\n", a-b, c, minWrap(a,b));
return EXIT_SUCCESS;
}
Which gave as output:
0xffffff02 0x02 0x02
I would have expected the output to be the same three times. My question is: is it always safe to add/subtract unsigned chars and expect them to wrap around at 0xff?
Or more general, is it safe to compute with uintN_t and expect the result to be modulo 2^N?
is it always safe to add/subtract unsigned chars and expect them to wrap around at 0xff?
No. In C, objects of type char go through the usual integer promotions. So if the range of char fits in int (usual), it is converts to int, else unsigned.
a - b --> 0x01 - 0xFF --> 1 - 255 --> -254.
The below is undefined behavior as %x does not match an int and the value of -254 is not in the unsigned range (See #EOF comment). A typical behavior is a conversion to unsigned
printf("0x%02x\n", a-b);
// 0xffffff02
it safe to compute with uintN_t and expect the result to be modulo 2^N?
Yes. But be sure to make the result of type uintN_t and avoid unexpected usual integer promotions.
#include <inttypes.h>
uint8_t a = 0x01, b = 0xff;
uint8_t diff = a - b;
printf("0x%02x\n", (unsigned) diff);
printf("0x%02" PRTx8 "\n", diff);
a-b in the printf line is evaluated after a and b are promoted to int. Also, the value is being treated as an unsigned int due to the use of %x in the format specifier by your run time environment.
It's equivalent to:
int a1 = a;
int b1 = b;
int x = a1 - b1;
printf("0x%02x 0x%02x 0x%02x\n", x, c, minWrap(a,b));
Section 6.3.1.8 Usual arithmetic conversions of the C99 standard has more details.
In theory use of an int when an unsigned int is expected in printf is cause for undefined behavior. A lenient run time environment, like you have, treats the int as an unsigned int and proceeds to print the value.
From 6.3.1.8/1 of the standard concerning integer conversions:
The integer promotions are performed on both operands. Then the following rules are applied to the promoted operands
If both operands have the same type, then no further conversion is
needed.
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, the wrap-around is well defined. In the expression a-b, because both operands are of type unsigned char, they are first promoted to int and the operation is performed. If this value was assigned to an unsigned char, it would be properly truncated. However, you're passing this value to printf with a %x format specifier which expects an unsigned int. To display it correctly, use %hhx which expects an unsigned char.
I have been preparing for interview when I bumped up with this question.
#include<stdio.h>
int main()
{
unsigned long a = 100;
long b = -1;
if(b>a)
printf("YES");
else
printf("No");
}
The output of the program is to be found. The answer is YES can anyone please explain me how this is the correct answer? I analyzed and found that the answer is YES when atleast one of a and b has unsigned qualifier. When both are just long then it prints NO
EDIT:
There is one other question which made me think much. Here is the code
#include<stdio.h>
int main()
{
float t = 1.0/3.0;
if(t*3 == 1.0)
printf("yes");
else
printf("no");
}
The answer for the code is no but I am not able to decipher how it is obtained. Also, when I assume a variable a = t*3 and compare it in the if statement, I get the output as yes
I am trying to learn the concepts. So Kindly help me by explaining how these 2 programs produce the respective output.
Thanks
When you do a comparison, the compiler has to convert both operands to the same type.
The conversion is based on "rank" (size) and signedness.
If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.
You compare an unsigned long with a long. According to the rule above, the long b is converted to unsigned long, resulting in the greatest possible positive number. Note, the actual bits do not change. 0xFFFFFFFF as a 32-bit signed means -1. As a 32-bit unsigned it means 4294967295.
As for the floats, the == operator compares the floats bit-by-bit. But you've lost some precision during the division and multiplication.
Because of C usual arithmetic conversions. Both operands of > operator are converted to a single common type. When
unsigned long a = 100;
long b = -1;
The if controlling expression:
b > a
is equivalent to
(unsigned long) b > a
which is equivalent here as:
ULONG_MAX > 100UL
because converting -1 to unsigned long evaluates to ULONG_MAX.
From usual arithmetic conversion:
"If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type."
before:
unsigned long -- signed long
100=...0001100100 -1 = ...11111111111
after:
unsigned long -- signed long converted to unsigned long
100 -- 2^n - 1
n- number of bits for long.
-1>100 ? No, 2^n -1 > 100.
Please look at my test code:
#include <stdlib.h>
#include <stdio.h>
#define PRINT_COMPARE_RESULT(a, b) \
if (a > b) { \
printf( #a " > " #b "\n"); \
} \
else if (a < b) { \
printf( #a " < " #b "\n"); \
} \
else { \
printf( #a " = " #b "\n" ); \
}
int main()
{
signed int a = -1;
unsigned int b = 2;
signed short c = -1;
unsigned short d = 2;
PRINT_COMPARE_RESULT(a,b);
PRINT_COMPARE_RESULT(c,d);
return 0;
}
The result is the following:
a > b
c < d
My platform is Linux, and my gcc version is 4.4.2.
I am surprised by the second line of output.
The first line of output is caused by integer promotion. But why is the result of the second line different?
The following rules are from C99 standard:
If both operands have the same type, then no further conversion is needed.
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.
I think both of the two comparisons should belong to the same case, the second case of integer promotion.
When you use an arithmetic operator, the operands go through two conversions.
Integer promotions: If int can represent all values of the type, then the operand is promoted to int. This applies to both short and unsigned short on most platforms. The conversion performed on this stage is done on each operand individually, without regard for the other operand. (There are more rules, but this is the one that applies.)
Usual arithmetic conversions: If you compare an unsigned int against a signed int, since neither includes the entire range of the other, and both have the same rank, then both are converted to the unsigned type. This conversion is done after examining the type of both operands.
Obviously, the "usual arithmetic conversions" don't always apply, if there are not two operands. This is why there are two sets of rules. One gotcha, for example, is that shift operators << and >> don't do usual arithmetic conversions, since the type of the result should only depend on the left operand (so if you see someone type x << 5U, then the U stands for "unnecessary").
Breakdown: Let's assume a typical system with 32-bit int and 16-bit short.
int a = -1; // "signed" is implied
unsigned b = 2; // "int" is implied
if (a < b)
puts("a < b"); // not printed
else
puts("a >= b"); // printed
First the two operands are promoted. Since both are int or unsigned int, no promotions are done.
Next, the two operands are converted to the same type. Since int can't represent all possible values of unsigned, and unsigned can't represent all possible values of int, there is no obvious choice. In this case, both are converted to unsigned.
When converting from signed to unsigned, 232 is repeatedly added to the signed value until it is in the range of the unsigned value. This is actually a noop as far as the processor is concerned.
So the comparison becomes if (4294967295u < 2u), which is false.
Now let's try it with short:
short c = -1; // "signed" is implied
unsigned short d = 2;
if (c < d)
puts("c < d"); // printed
else
puts("c >= d"); // not printed
First, the two operands are promoted. Since both can be represented faithfully by int, both are promoted to int.
Next, they are converted to the same type. But they already are the same type, int, so nothing is done.
So the comparison becomes if (-1 < 2), which is true.
Writing good code: There's an easy way to catch these "gotchas" in your code. Just always compile with warnings turned on, and fix the warnings. I tend to write code like this:
int x = ...;
unsigned y = ...;
if (x < 0 || (unsigned) x < y)
...;
You have to watch out that any code you do write doesn't run into the other signed vs. unsigned gotcha: signed overflow. For example, the following code:
int x = ..., y = ...;
if (x + 100 < y + 100)
...;
unsigned a = ..., b = ...;
if (a + 100 < b + 100)
...;
Some popular compilers will optimize (x + 100 < y + 100) to (x < y), but that is a story for another day. Just don't overflow your signed numbers.
Footnote: Note that while signed is implied for int, short, long, and long long, it is NOT implied for char. Instead, it depends on the platform.
Taken from the C++ standard:
4.5 Integral promotions [conv.prom] 1 An rvalue of type char, signed char, unsigned char, short int, or unsigned short int can be
converted to an rvalue of type int if int can represent all the values of the
source type; otherwise, the source rvalue can be converted to an
rvalue of type unsigned int.
In practice it means, that all operations (on the types in the list) are actually evaluated on the type int if it can cover the whole value set you are dealing with, otherwise it is carried out on unsigned int.
In the first case the values are compared as unsigned int because one of them was unsigned int and this is why -1 is "greater" than 2. In the second case the values a compared as signed integers, as int covers the whole domain of both short and unsigned short and so -1 is smaller than 2.
(Background story: Actually, all this complex definition about covering all the cases in this way is resulting that the compilers can actually ignore the actual type behind (!) :) and just care about the data size.)
The conversion process for C++ is described as the usual arithmetic conversions. However, I think the most relevant rule is at the sub-referenced section conv.prom: Integral promotions 4.6.1:
A prvalue of an integer type other than bool, char16_t, char32_t, or
wchar_t whose integer conversion rank ([conv.rank]) is less than the
rank of int can be converted to a prvalue of type int if int can
represent all the values of the source type; otherwise, the source
prvalue can be converted to a prvalue of type unsigned int.
The funny thing there is the use of the word "can", which I think suggests that this promotion is performed at the discretion of the compiler.
I also found this C-spec snippet that hints at the omission of promotion:
11 EXAMPLE 2 In executing the fragment
char c1, c2;
/* ... */
c1 = c1 + c2;
the ``integer promotions'' require that the abstract machine promote the value of each variable to int size
and then add the two ints and truncate the sum. Provided the addition of two chars can be done without
overflow, or with overflow wrapping silently to produce the correct result, the actual execution need only
produce the same result, possibly omitting the promotions.
There is also the definition of "rank" to be considered. The list of rules is pretty long, but as it applies to this question "rank" is straightforward:
The rank of any unsigned integer type shall equal the rank of the
corresponding signed integer type.
I was reading in the C99 standard about the usual arithmetic conversions.
If both operands have the same type, then no further conversion is
needed.
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.
So let's say I have the following code:
#include <stdio.h>
int main()
{
unsigned int a = 10;
signed int b = -5;
printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */
return 0;
}
I thought the bolded paragraph applies (since unsigned int and signed int have the same rank. Why isn't b converted to unsigned ? Or perhaps it is converted to unsigned but there is something I don't understand ?
Thank you for your time :-)
Indeed b is converted to unsigned. However what you observed is that b converted to unsigned and then added to 10 gives as value 5.
On x86 32bit this is what happens
b, coverted to unsigned, becomes 4294967291 (i.e. 2**32 - 5)
adding 10 becomes 5 because of wrap-around at 2**32 (2**32 - 5 + 10 = 2**32 + 5 = 5)
0x0000000a plus 0xfffffffb will always be 0x00000005 regardless of whether you are dealing with signed or unsigned types, as long as only 32 bits are used.
Repeating the relevant portion of the code from the question:
unsigned int a = 10;
signed int b = -5;
printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */
In a + b, b is converted to unsigned int, (yielding UINT_MAX + 1 - 5 by the rule for unsigned-to-signed conversion). The result of adding 10 to this value is 5, by the rules of unsigned arithmetic, and its type is unsigned int. In most cases, the type of a C expression is independent of the context in which it appears. (Note that none of this depends on the representation; conversion and arithmetic are defined purely in terms of numeric values.)
For the second printf call, the result is straightforward: "%u" expects an argument of type unsigned int, and you've given it one. It prints "5\n".
The first printf is a little more complicated. "%d" expects an argument of type int, but you're giving it an argument of type unsigned int. In most cases, a type mismatch like this results in undefined behavior, but there's a special-case rule that corresponding signed and unsigned types are interchangeable as function arguments -- as long as the value is representable in both types (as it is here). So the first printf also prints "5\n".
Again, all this behavior is defined in terms of values, not representations (except for the requirement that a given value has the same representation in corresponding signed and unsigned types). You'd get the same result on a system where signed int and unsigned int are both 37 bits, signed int has 7 padding bits, unsigned int has 11 padding bits, and signed int uses a 1s'-complement or sign-and-magnitude representation. (No such system exists in real life, as far as I know.)
It is converted to unsigned, the unsigned arithmetic just happens to give the result you see.
The result of unsigned arithmetic is equivalent to doing signed arithmetic with two's complement and no out of range exception.