I don't understand why the variable have value of 0, it should be 23?
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int array[] = {23, 34, 12, 17, 204, 99, 16};
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int main(){
int d = -1, x = 0;
if (d <= TOTAL_ELEMENTS - 2)
x = array[d + 1];
printf("x= %d \n", x);
return 0;
}
This is due to the usual arithmetic conversions.
When the operands of a operator involve both a signed integer and an unsigned integer, and the unsigned type is at least as large as the signed type, the signed value is converted to an unsigned value. When the signed value is negative, it gets converted to a large positive value.
The rules for integer conversions are spelled out in section 6.3.1.8p1 of the C 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
In this expression:
(d <= TOTAL_ELEMENTS - 2)
Which expands to:
(d <= (sizeof(array) / sizeof(array[0])) - 2)
The sizeof operator evaluates to a value of type size_t which is unsigned. So the types of the operands look like this:
(int <= ((size_t / size_t) - int)
Both operands of the / operator are of type size_t so the result of that operation is of type size_t. Then the right operand of - is converted to type size_t. Since the value 2 fits in that type the value doesn't change.
Now we have the <= operator with an int on one size and a size_t on the other. The left operand is converted from int to size_t, however the value -1 doesn't fit in that type so it is converted. The converted value is actually the largest possible value for a size_t which is therefore greater than the value on the right side, making the result of <= false.
To fix this, you'll want to cast the unsigned value on the right to signed to prevent the left side from being converted:
if (d <= (int)(TOTAL_ELEMENTS - 2))
Related
I'm confused by the issue stated in the title. I've been told that in expressions involving both types of variables, signed are converted to/interpreted as unsigned. However, as the following code snippet shows, that isn't always the case.
Code:
unsigned int x = 1;
int y = -20;
printf("Right shift = %x, %d\n", y>>x, y>>x);
printf("If = %x, %d\n", y < x, y < x);
Result:
Right shift = fffffff6, -10
If = 0, 0
The if statement returns the expected 0, -20 being cast to a very large unsigned integer, but the shift expression returns -10, making it evident that arithmetic and not logical shift has taken place. The x has been interpreted as signed rather than the y being interpreted as unsigned.
Could anyone clear this up for me?
In this expression
y>>x
(the C Standard, 6.5.7 Bitwise shift operators)
3 The integer promotions are performed on each of the operands.
That means that as y has the type int and x has the type unsigned int neither conversion (promotion) occurs. And
...The type of the result is that of the promoted left operand.
So the result of the expression has the type int - the type of the operand y. As y has a negative value then
...IfE1 has a signed type and a negative value, the resulting value is
implementation-defined
As for this expression
y < x
then there is used the usual arithmetic conversions. The boths operands have the same rank so the operand y of the type int is converted to the type unsigned int and its binary representation as an object of the type unsigned int is greater than the binary representation of the operand x.
From the C Standard *6.3.1.8 Usual arithmetic conversions)
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.
Lets say I have 3 variables: a long, an int and a short.
long l;
int i;
short s;
long lsum;
If this is a pure math, since multiplication has a commutative property, the order of these variables doesn't matter.
l * i * s = i * s * l = s * i * l.
Let lsum be the container of the multiplication of these 3 variables.
In C, would there be a case where a particular order of these variables cause different result?
If there is a case where the order does matter, not necessarily from this example, what would that be?
The order does matter due to integer promotions.
When applying an arithmetic operator, each of its operands is first promoted to int if its rank is less than int (such as char or short). If one of those operands then has a higher rank still (such as long), than the smaller is promoted.
From section 6.3.1 of the C standard:
2 The following may be used in an expression wherever an int or unsigned int may be used:
An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to
the rank of int and unsigned int.
A bit-field of type _Bool, int, signed int, or unsigned int.
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. All other types are unchanged by the integer
promotions.
From section 6.3.1.8:
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.
As an example (assuming sizeof(int) is 4 and sizeof(long) is 8):
int i;
short s;
long l, result;
i = 0x10000000;
s = 0x10;
l = 0x10000000;
result = s * i * l;
printf("s * i * l=%lx\n", result);
result = l * i * s;
printf("l * i * s=%lx\n", result);
Output:
s * i * l=0
l * i * s=1000000000000000
In this example, s * i is evaluated first. The value of s is promoted to int, then the two int values are multiplied. At this point an overflow occurs unvoking undefined behavior. The result is then promoted to long and multiplied by l, with the result being of type long.
In the latter case, l * i is evaluated first. The value of i is promoted to long, then the two long values are multiplied and an overflow does not occur. The result is then multiplied by s, which is first promoted to long. Again, the result does not overflow.
In a situation like this, I'd recommend casting the leftmost operand to long so that all other operands are promoted to that type. If you have parenthesized subexpressions you may need to apply a cast there as well, depending on the result you want.
Yes, see "Type conversion" and "Type promotion" on http://www.cplusplus.com/articles/DE18T05o/
unsigned a = INT_MAX;
unsigned b = INT_MAX;
unsigned long c = 255;
unsigned long r1 = a * b * c;
unsigned long r2 = c * a * b;
r1=255
r2=13835056960065503487
r1 reflects that (a*b) is done first with types as least as long as an int, and the result is of the longest operand type, which is unsigned, so the result is unsigned and that overflows.
This question already has answers here:
Why is −1 > sizeof(int)?
(4 answers)
Closed 6 years ago.
The following program compiles successfully but when i ran it ,it prints nothing when i initialize the for loop with -1 but when i initialize for loop with 0 it successfully traverse all the array.I want to ask that can we don't traverse the array when we initialize the for loop with negative value??
#include <stdio.h>
#define TOTAL_ELEMENTS (sizeof(array) / sizeof(array[0]))
int array[] = {23, 34, 12, 17, 204, 99, 16};
int main(void) {
int d;
//printf("%d",TOTAL_ELEMENTS);
for (d = -1; d <= (TOTAL_ELEMENTS - 2); d++)
{
printf("%d ",d);
printf("%d\n", array[d+1]);
}
return 0;
}
The result of sizeof operator is of type size_t, which is an unsigned type.
As a result, the type of TOTAL_ELEMENTS is also unsigned. When -1 is compared with it, it's converted to a big unsigned number. That's why d <= (TOTAL_ELEMENTS - 2) is false.
Here d <= (TOTAL_ELEMENTS - 2) operands are subject of usual arithmetic conversions (6.3.1.8). And actually integer promotions rules act in your case:
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.
According to what you've got your code falls into clause #3, then your signed -1 is converted via rule (6.3.1.3):
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.
As result it becomes a very large unsigned value, that is surely greater than TOTAL_ELEMENTS - 2 and you'll never enter the loop.
This doesn't do what you think it does:
d <= (TOTAL_ELEMENTS - 2)
Instead, do this:
d <= int(TOTAL_ELEMENTS - 2)
Otherwise you've got a signed-vs-unsigned comparison, and your -1 becomes the largest possible size_t.
sizeof produces a result of size_t, which is unsigned. Compare a signed and unsigned type and you can only expect things to blow up.
To elaborate, when you try to use both signed and unsigned type in arithmatic operations, the signed type will be promoted to unsigned type, producing a huge number. Thus, the value of d , promoted to unsigned type, will fail to meet the condition d <= (TOTAL_ELEMENTS - 2);, hence the loop body will not execute.
For operators that expect operands of arithmetic type cause conversions. This pattern is called the usual arithmetic conversions. for this particular case, quoting the standard, chapter §6.3.1.8
Otherwise, the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
[...]
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.
and, regarding the rank,
The rank of any unsigned integer type shall equal the rank of the corresponding
signed integer type, if any.
Also, for reference, quoting C11, chapter 7.19, (emphasis mine)
size_t
which is the unsigned integer type of the result of the sizeof operator;
Hint: Enable compiler warning and it will point to your mistake.
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.
I am trying to compare an unsigned int with a signed char like this:
int main(){
unsigned int x = 9;
signed char y = -1;
x < y ? printf("s") : printf("g");
return 0;
}
I was expecting the o/p to be "g". Instead, its "s". What kind of conversion is done here?
Section 6.3.1.8, Usual arithmetic conversions, of C99 details implicit integer conversions.
If both operands have the same type, then no further conversion is needed.
That doesn't count since they're different types.
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.
That doesn't count since one is signed, the other unsigned.
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.
Bingo. x has a higher rank than y so y is promoted to unsigned int. That means that it morphs from -1 into UINT_MAX, substantially larger than 9.
The rest of the rules don't apply since we have found our match but I'll include them for completeness:
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.
The ranks relevant to this question are shown below. All ranks are detailed in C99, section 6.3.1.1, Boolean, character, and integers so you can refer to that for further details.
The rank of long long int shall be greater than the rank of long int, which
shall be greater than the rank of int, which shall be greater than the rank of short int, which shall be greater than the rank of signed char.
The rank of char shall equal the rank of signed char and unsigned char.
My guess is y is promoted to unsigned int which becomes a big value (due to wrapping). Hence the condition is satisfied.
Ran the following code:
int main(){
unsigned int x = 9;
signed char y = -1;
printf("%u\n", (unsigned int)y);
x < (unsigned int)y ? printf("s") : printf("g");
return 0;
}
The output is:
4294967295
s
After a casting, y takes a very large value. That is why output is s.
The char is promoted to unsigned int, with a value of MAX_UINT, which is greater than 9.