This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Unsigned and signed comparison
unsigned int and signed char comparison
I have a strange behavior when i try to enter in this while statement:
unsigned u = 0;
int i = -2;
while(i < u)
{
// Do something
i++;
}
But it never enters, even if when i set a break point i = -2 and u = 0.
What am I doing wrong? How could i fix this?
It's because the ANSI C standard defines that whenever there is a comparison between a qualified (your unsigned int u) and a non qualified type (your int i), the non qualified type gets promoted to a type of the same type (thus always int), but also inherits the qualifiers of the other quantity (i.e. it becomes unsigned).
When your int, whose value is equal to -2, becames unsigned the first byte undergoes this transformation: 0000 0010 -> 1111 1110. Your int is now a very large positive number, certainly larger of your unsigned int.
There is a solution: cast to signed
while(i < (signed) u)
{
// Do something
i++;
}
By the way, probably your compiler should give you a warning.
You are comparing a signed and unsigned integer and your problems started there...
Don't do that and it should work just fine.
Related
I'm pretty much assuming this is a stupid question... but I can't really find the answer for it. So I'm asking this here.
For the purpose of learning about implicit type casting, I'm running the following code on C.
#include <stdio.h>
int main()
{
unsigned char i;
char cnt = -1;
int a[255];
for (int k = 0; k < 255; k++)
{
a[k] = k;
}
for (i = cnt - 2; i < cnt; i--)
{
a[i] += a[i + 1];
printf("%d\n", a[i]);
}
return 0;
}
When I ran this program, nothing happened.
I was able to found out that the loop condition of for-loop was false at the first iteration, so the program exited the for-loop right away.
However, I don't get the reason why.
As far as I know, C does implicit casting when assigning or comparing variables with different types. So I thought that on i = cnt - 2, the minus operation makes the value -3, and then implicit casting assigns i with a value 253.
Then, shouldn't the condition i < cnt be true since (by another implicit casting of cnt because of comparison of signed and unsigned char) 253 is smaller than 255?
If it isn't, why is this false? Is there something that I missed or is there some exception that I don't know?
Your question is not stupid at all. You were close to the solution: i is assigned the value -3 but the implicit conversion to the type of i, unsigned char, changes the value to 253.
For a more precise explanation, there are multiple issues in your test code:
char may be signed or unsigned depending on the platform and compiler configuration, so char cnt = -1; may store the value -1 or 255 into cnt, or even some other value if char is unsigned and has more than 8 bits.
The behavior of for (i = cnt - 2; i < cnt; i--) also depends on whether char is signed or unsigned by default:
in all cases, the test i < cnt is evaluated with both operands converted to int (or unsigned int in the rare case where sizeof(int)==1). If int can represent all values of types char and unsigned char, this conversion does not change the values.
if char is unsigned and has 8 bits, cnt has the value 255 so i is initialized with the value 253 and the loop runs 254 times with i from 253 down to 0, then i-- stores the value 255 again into i, for which the test i < cnt evaluates to false. The loop prints 507, then 759, ... 32385.
if char is signed and has 8 bits, as is probably the case on your system, cnt has the value -1 and i is initialized with the value -3 converted to unsigned char, which is 253. The initial test i < cnt evaluates as 253 < -1, which is false, causing the loop body to be skipped immediately.
You can force char to be unsigned by default by giving the compiler the appropriate flag (eg: gcc -funsigned-char) and test how the behavior changes. Using Godbolt's compiler explorer, you can see that gcc generates just 2 instructions to return 0 in the signed (default) case and the expected output in the unsigned case.
For starters let's assume that the type char behaves as the type
signed char.
In this condition
i < cnt
the both operands are implicitly converted to the type int due to the integer promotions.
From the C Standard (6.5.8 Relational operators)
3 If both of the operands have arithmetic type, the usual arithmetic
conversions are performed.
and (6.3.1.8 Usual arithmetic conversions)
1 Many operators that expect operands of arithmetic type cause
conversions and yield result types in a similar way. The purpose is to
determine a common real type for the operands and result. For the
specified operands, each operand is converted, without change of type
domain, to a type whose corresponding real type is the common real
type. Unless explicitly stated otherwise, the common real type is also
the corresponding real type of the result, whose type domain is the
type domain of the operands if they are the same, and complex
otherwise. This pattern is called the usual arithmetic conversions:
...
Otherwise, 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
and (6.3.1.1 Boolean, characters, and integers)
...If an int can represent all values of the original type (as restricted
by the width, for a bit-field), the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the
integer promotions.
Thus the positive value of i represented like 0000 0000 1111 1101 after the integer promotions will be greater than the negative value 1111 1111 1111 1111.
So the condition of the for loop at once evaluates to logical false because the positive value 253 of the type int is greater than the negative value -1 of the type int.
Here is a demonstrative program.
#include <stdio.h>
int main(void)
{
char cnt = -1;
unsigned char i = cnt - 2;
printf( "cnt = %x\n", ( unsigned int )cnt );
printf( "i = %x\n", ( unsigned int )i );
printf ( "i < cnt is %s\n", i < cnt ? "true" : "false" );
return 0;
}
The program output is
cnt = ffffffff
i = fd
i < cnt is false
This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
Closed 1 year ago.
#include <stdio.h>
int main() {
unsigned int i = 23;
signed char c = -23;
if (i<c)
puts("TRUE");
return 0;
}
Why the output of the following program is TRUE, even though I have used signed char which can store from -128 to 127.
Your i < c comparison has operands of two different types, so the operand with the smaller type (lower rank) is converted to the type of the other. In this case, as -23 cannot be represented as an unsigned int, and following the "usual arithmetic conversions," it will end up with a value considerably greater than +23 (actually, UINT_MAX + 1 - 23), according to Paragraph #2 in the following excerpt from this (Draft) C11 Standard:
6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than _Bool, if the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by
repeatedly adding or subtracting one more than the maximum value that
can be represented in the new type until the value is in the range of
the new type.
3 Otherwise, the new type is signed and the
value cannot be represented in it; either the result is
implementation-defined or an implementation-defined signal is
raised.
You can see this conversion in action by assigning c to a separate unsigned int and printing its value, as in the following code. Assuming a 32-bit unsigned int, you will likely see a value of 4294967273 (which is, indeed, greater than 23).
#include <stdio.h>
int main()
{
unsigned int i = 23;
signed char c = -23;
unsigned int uc = c; // Add a diagnostic line ...
printf("%u\n", uc); // ... and show the value being used in the comparison
if (i < c) {
printf("TRUE");
}
return 0;
}
Note: The relative size of the two variables (i and c) here is something of a red herring; even if you declare c as signed int c = -23;, you will still get the same result, due to the Usual Arithmetic Conversions (link courtesy of Jonathan Leffler's comment) – note that a signed int cannot represent all possible values of an unsigned int, so the very last of the 'hollow' bullets will come into play.
In order to make the comparison, the smallest variable (char, 8 bit) must be promoted to the size and signedness of the larger one (integer, 32 bit). But in so doing, -23 becomes 4294967273. Which is much more than 23.
If you compare c with a signed integer, the sign promotion causes no change and the test behaves as expected.
This question already has answers here:
What happens if I assign a negative value to an unsigned variable?
(7 answers)
Assigning negative numbers to an unsigned int?
(14 answers)
Closed 3 years ago.
I have assigned -1 to unsigned int and assuming it would produce an error I compiled the code, much to my astonishment it didn't. I can't understand the reason behind it.
I have tried printing the values to check them manually, but it always shows -1.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, char *argv[]) {
unsigned int x = -1;
printf("%u\n", x);
int y = -1;
printf("%d\n", y);
if (x == y) {
printf("\nsame");
} else {
printf("n s");
}
return 0;
}
the expected result would have been an error or a warning
but it compiled as is.
It works because this:
unsigned int x = -1;
causes the int-typed literal -1 to be converted to an unsigned int which is a standard, well-specified, conversion. The draft C11 spec says:
6.3.1.3 Signed and unsigned integers
1 When a value with integer type is converted to another integer type other than
_Bool, if the value can be represented by the new type, it is unchanged.
2 Otherwise, if the new type is unsigned, the value is converted by repeatedly
adding or
subtracting one more than the maximum value that can be represented in the new
type until the value is in the range of the new type.60)
The latter is what is happening here, so assuming 32-bit integers 232 is being added, making the result 0xffffffff.
I don't believe that the printf() with %u prints -1, that would be a rather major bug.
This is allowed by the standard. When you assign -1 to the unsigned type, conceptually at least, the value is converted to a number that can be represented by the repeated addition of 2n where n is the number of bits in that type.
This conversion also happens to the signed type in the comparison x == y (that comparison takes place in unsigned arithmetic since one of the variables is an unsigned type).
This question already has answers here:
Why is a negative int greater than unsigned int? [duplicate]
(6 answers)
Closed 5 years ago.
Given that code :
int main(void) {
long x = -1;
if (x < sizeof(x)) {
printf("OK\n");
}
else {
printf("Not Ok\n");
}
return 0;
}
Prints:
Not Ok
I have read about usual arithmetic conversions, and from what i understood that if we have a comparison between two operands with different data types, the compiler invokes a data coercion on the operand which is narrower than the other operand, which will convert the the sizeof(x) into unsigned int to match the other operand, any thoughts?
Aside question:
I tried to do casting size(x) as int in the comparison expression as:
if(x < (int) size(x))
It prints Ok, which I find very strange!
You should never compare a signed number to an unsigned number. Add a compiler switch to warn you about this.
Here, in your case, x will be converted to unsigned, -1 becomes SIZE_MAX (the largest number a that std::size_t can hold). It is because sizeof returns an unsigned number (it returns std::size_t, which is unsigned)
The other thing that could happen, but don't happen in practice is that if sizeof(long)>sizeof(std::size_t) then sizeof(x) would be converted to long, so your program would print OK.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
A riddle (in C)
1.
main()
{
if(-1<(unsigned char)1)
printf("-1 is less than (unsigned char)1:ANSI semantics");
else
printf("-1 NOT less than (unsigned char)1:K&R semantics");
}
2.
int array[] = {23,41,12,24,52,11};
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0]))
main()
{
int d = -1,x;
if(d<=TOTAL_ELEMENTS -2)
x = array[d+1];
}
The first convert unsigned char 1 to a signed variable in ANSI C,
while the second program convert d to an unsigned int that makes the
condition expression return false in ANSI C.
Why did they behave differently?
For the first one the right-hand side is an unsigned char, and all unsigned char values fit into a signed int, so it is converted to signed int.
For the second one the right-hand side is an unsigned int, so the left-hand side is converted from signed int to unsigned int.
See also this CERT document on integer conversions.
starblue explained the first part of your question. I'll take the second part. Because TOTAL_ELEMENTS is a size_t, which is unsigned, the int is converted to that unsigned type. Your size_t is so that int cannot represent all values of it, so the conversion of the int to size_t happens, instead of the size_t to the int.
Conversion of negative numbers to unsigned is perfectly defined: The value wraps around. If you convert -1 to an unsigned int, it ends up at UINT_MAX. That is true whether or not you use twos' complement to represent negative numbers.
The rationale for C document has more information about that value preserving conversion.
Here's the way I remember how automatic conversions are applied:
if the operand sizes are different, the conversion is applied to the smaller operand to make it the same type as the larger operand (with sign extension if the smaller operand is signed)
if the operands are the same size, but one is signed and the other unsigned, then the signed operand is converted to unsigned
While the above may not be true for all implementations, I believe it is correct for all twos-complement implementations.