This question already has answers here:
Signed/unsigned comparisons
(6 answers)
Why is a negative int greater than unsigned int? [duplicate]
(6 answers)
Closed 9 years ago.
I'm puzzled. Example:
int x=-1;
unsigned y=0;
(x<y) ----> false
int8_t x=-1;
unint8_t y=0;
(x<y) ----> true
Additionally, the compiler raises warnings on the first comparison, but not the second. It seems that for
(int vs unsigned) - int promoted to unsigned
(intN_t vs uintN_t) - uintN_t promoted to intN_t
Why have this behaviour? Like... really?
Whenever you apply any binary arithmetic operator (including comparisons) to a pair of numeric types which are both shorter than int, C converts both operands to int before performing the operation.
Whenever you apply any binary arithmetic operator to a pair of numeric types which are the same size, mismatched in signedness, and not shorter than int, C converts the signed operand to unsigned before the operation.
These are two of the "integer promotion" rules. They are not terribly intuitive, and they are probably not what one would do if one were designing C from scratch today, but they are what they are and we are stuck with them.
This is a result of the usual integer conversions.
In the first case, both operands have rank at least that of int, and have the same rank, so they are converted to the unsigned integer type.
In the second case, int8_t is char (it has to be, if it exists at all), so both operands are promoted to int. Both -1 and 0 are representable in int, so there is no warning.
Related
This question already has answers here:
unsigned int and signed char comparison
(4 answers)
Closed 6 years ago.
I came across this question.
#include <stdio.h>
int main(void) {
// your code goes here
unsigned int i = 23;
signed char c = -23;
if (i > c)
printf("yes");
else
printf("no");
return 0;
}
I am unable to understand why the output of this code is no.
Can someone help me in understanding how the comparison operator works when comparison is done between int and char in C ?
You are comparing an unsigned int to a signed char. The semantics of this kind of comparison are counter-intuitive: most binary operations involving signed and unsigned operands are performed on unsigned operands, after converting the signed value to unsigned (if both operands have the same size after promotion). Here are the steps:
The signed char value is promoted to an int with the same value -23.
comparison is to be performed on int and unsigned int, the common type is unsigned int as defined in the C Standard.
The int is converted to an unsigned int with value UINT_MAX - 23, a very large number.
The comparison is performed on the unsigned int values: 23 is the smaller value, the comparison evaluates to false.
The else branch is evaluated, no is printed.
To make matters worse, if c had been defined as a long, the result would have depended on whether long and int have the same size or not. On Windows, it would print no, whereas on 64 bit Linux, it would print yes.
Never mix signed and unsigned values in comparisons. Enable compiler warnings to prevent this kind of mistake (-Wall or -Weverything). You might as well make all these warnings fatal with -Werror to avoid this kind of ill-fated code entirely.
For a complete reference, read the following sections of the C Standard (C11) under 6.3 Conversions:
integer promotions are explained in 6.3.1.1 Boolean, characters, and integers.
operand conversions are detailed in 6.3.1.8 Usual arithmetic conversions.
You can download the latest draft of the C11 Standard from the working group website: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
Closed 6 years ago.
Following snippet of code is not working as I expected, the output of the following program is "S is Bigger" when compiled with GCC in an Ubuntu machine. Although the variable s is -1 and which is clearly smaller than sizeof(buffer) which is 20. But still it prints S is Bigger.
Only logical assumption I can make is that C is converting the variable "s" to unsigned integer and using in "If" condition.
If My assumption is correct why C is doing that or if I am wrong why this snippet is giving this confusing output.
#include <stdio.h>
int main(void) {
int s = -1;
char buffer[20];
if(s > sizeof(buffer)){
printf("S is Bigger");
}
return 0;
}
From the answer to this question
It's safe provided the int is zero or positive. If it's negative, and size_t is of equal or higher rank than int, then the int will be converted to size_t and so its negative value will instead become a positive value.
sizeof() returns size_t
You are correct, the compiler converts s to the unsigned int data type size_t (which is the return value of sizeof operator). So the comparison become (on my system where size_t is 64 bit):
if (18446744073709551615 > 20)
which is clearly true ;)
This is part of the Implicit conversions defined by the standard. The relevant section is the "Usual arithmetic conversions" which is in 6.3.1.8 of the standard.
See also this post and this other post
Foundamental rules:
If both operands have the same type, no further conversion is needed.
If both operands are of the same integer type (signed or unsigned), the operand with the type of lesser integer conversion rank is converted to the type of the operand with greater rank.
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.
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, 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.
This question already has answers here:
Comparison operation on unsigned and signed integers
(7 answers)
In a C expression where unsigned int and signed int are present, which type will be promoted to what type?
(2 answers)
Closed 7 years ago.
This is the code,
#include <stdio.h>
int main()
{
unsigned int i = 0xFFFFFFFF;
if (i == -1)
printf("signed variable\n");
else
printf("unsigned variable\n");
return 0;
}
This is the output,
signed variable
Why is i's value -1 even it is declared as unsigned?
Is it something related to implicit type conversations?
This is the build environment,
Ubuntu 14.04, GCC 4.8.2
The == operator causes its operands to be promoted to a common type according to C's promotion rules. Converting -1 to unsigned yields UINT_MAX.
i's value is 0xFFFFFFFF, which is exactly the same as -1, at least when the later is converted to an unsigned integer. And this is exactly what is happening with the comparison operators:
If both of the operands have arithmetic type, the usual arithmetic conversions are performed. [...]
[N1570 $6.5.9/4]
-1 in two's complement is "all bits set", which is also what 0xFFFFFFFF for an unsigned int (of size 4) is.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Confused about C macro expansion and integer arithmetic
A riddle (in C)
The expected output of the following C program is to print the elements in the array. But when actually run, it doesn't do so.
#include<stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23,34,12,17,204,99,16};
int main()
{
int d;
for(d=-1;d <= (TOTAL_ELEMENTS-2);d++)
printf("%d\n",array[d+1]);
return 0;
}
Because sizeof gives you an unsigned value, which you probably would have noticed had you turned up the warning level, such as using -Wall -Wextra with gcc (a):
xyzzy.c: In function 'main':
xyzzy.c:8: warning: comparison between signed and unsigned
If you force it to signed, it works fine:
#define TOTAL_ELEMENTS (int)((sizeof(array) / sizeof(array[0])))
What happens in detail can be gleaned from the ISO standard. In comparisons between different types, promotions are performed to make the types compatible. The compatible type chosen depends on several factors such as sign compatibility, precision and rank but, in this case, it was deemed that the unsigned type size_t was the compatible type so d was upgraded to that type.
Unfortunately, casting -1 to an unsigned type (at least for two's complement which is almost certainly what you're using) results in a rather large positive number.
One that's certainly larger the the 5 you get from (TOTAL_ELEMENTS-2). In other words, your for statement effectively becomes:
for (d = some big honking number way greater than five;
d <= 5;
d++
) {
// fat chance of getting in here !!
}
(a) This requirement to use extra remains a point of contention between the gcc developers and myself. They're obviously using some new definition of the word "all" of which I was previously unaware (with apologies to Douglas Adams).
TOTAL_ELEMENTS is of type size_t, subtracting 2 is done at compile time and so it is 5UL (emphasis on the unsigned suffix). The comparison with the signed integer d is then always false. Try
for(d=-1;d <= (ssize_t)(TOTAL_ELEMENTS-2);d++)
FTW, the intel compiler warns about exactly this when you try and compile the code.
To clarify what went wrong: sizeof() translates to a result type of size_t, which is nothing but an unsigned integer, larger than or equal to unsigned int.
So the result of (sizeof(array) / sizeof(array[0])) is a result in two operands of size_t type. The division is performed on these operands:size_t / size_t. Both operands are of the same type so it works fine. The result of the division is of type size_t, which is the type that TOTAL_ELEMENTS results in.
The expression (TOTAL_ELEMENTS-2) therefore have the types size_t - int, since the integer literal 2 is of type int.
Here we have two different types. What happens then is something called balancing (formally "the usual arithmetic conversions"), which happens when the compiler spots two different types. The balancing rules state that if one operand is signed and the other unsigned, then the signed one is silently, implicitly converted to an unsigned type.
This is what happens in this code. size_t - int is converted to size_t - size_t, then the subtraction is executed, the result is size_t. Then int <= size_t is converted to size_t <= size_t. The variable d turns unsigned, and if it had a negative value, the code goes haywire.
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.