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.
Related
In the code below the sizeof(int) will produce a signed int with a value of 4 bytes (suppose on a particular compiler) and -1 is also signed int, then my answer should be Yes but it displays No.
#include <stdio.h>
int main()
{
if (sizeof(int) > -1)
printf("Yes");
else
printf("No");
return 0;
}
Well it is the famous signed unsigned comparison. Here -1 which is signed number when compared to unsigned numbers - promoted to an unsigned number resulting in a big magnitude value (SIZE_MAX). So it is always false.
The explanation why there would be type promotion here when comparing:
From standard §6.3.1.8
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.
Also from §6.5.8 under relational operators
If both of the operands have arithmetic type, the usual arithmetic
conversions are performed.
And what sizeof returns?
Under The sizeof and _Alignof operators §6.5.3.4
The value of the result of both operators is implementation-defined, and its type (an unsigned integer type) is
size_t, defined in (and other headers).
And in section §7.19 under Common definitions
size_t which is the unsigned integer type of the result of the sizeof
operator;
To clarify a bit further when you are converting -1 to size_t it will have the value (Basically modulo SIZE_MAX+1)
SIZE_MAX+1+(-1)
Also from standard §6.2.5 (Explaining the conversion)
A computation involving unsigned operands can never overflow, because
a result that cannot be represented by the resulting unsigned integer
type is reduced modulo the number that is one greater than the largest
value that can be represented by the resulting type.
#include <stdio.h>
int main()
{
short int a;
char c;
printf("%d %d %d",sizeof(a),sizeof(c),sizeof(c+a));
}
In this sizeof a is 2 byte size of char is 1 byte but i add them up it is giving 4 byte. what it is doing inside the expression to make it 4
Adding a short int to a char results in an int, which apparently is 4 bytes on your system.
This is a case if "integer promotion". See In a C expression where unsigned int and signed int are present, which type will be promoted to what type? for an explanation. The rules are rather confusing, but the answers there explain it rather well.
Per 6.3.1.8 Usual arithmetic conversions of the C standard, the actual conversion rule is:
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.
The result is 4, because, as #WeatherVane noted in the comments:
5.1.2.3 para 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. But there is no truncation here because the destination is unknown.
sizeof returns the size of the object representation after it has been evaluated. The expression c+a apparently returns an int, which is four bytes. I think what you are looking for is:
sizeof(c) + sizeof(a)
When integral types like char, short int, bool take less number of bytes than int, then these data types are automatically promoted to int or unsigned int when an operation is performed on them.
C11 §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. 58)
So, c+a are converted to type int and the result has this common type of operands that is int.
Also, the behaviour of your code is undefined, because you have used the wrong format specifier.
So, use %zu instead of %d because sizeof() returns size_t and size_t is unsigned.
C11 Standard: §7.21.6.1: Paragraph 9:
If a conversion specification is invalid, the behavior is
undefined. 225) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
For the mathematically inclined (and because it occurred to me to wonder when such a thing might ever be true):
The misapprehension that is OP is labouring under is that
f(x) + f(y) = f(x+y)
which is certainly not true for sizeof() for the reasons Tom points out in the comments.
The class of functions for which it is true are called Additive Maps
Typical examples include maps between rings, vector spaces, or modules that preserve the additive group.
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.
Someone was talking with me about wraparound in C (0xffff + 0x0001 = 0x0000), and it led me to the following situation:
int main() {
unsigned int a;
for (a = 0; a > -1; a++)
printf("%d\n", a);
return 0;
}
Compiling with GCC, this program exits without running the loop, which I assume is because -1 was implicitly cast to 0xffff. The same happens when switching int to long. However, when switching to char, the program runs indefinitely. I would expect that since the int did not run the loop, neither would the char. Can someone explain what sort of implicit casting the compiler is performing in this situation, and is it defined in one of the editions of the C standard or is it compiler-dependent?
In C, unsignedness is sticky:
unsigned int a;
/* ... */
a > -1
in the above > expression, the left operands is of type unsigned int and the right operand is of type int. The C usual arithmetic conversions convert the two operands to a common type: unsigned int and so the > expression above is equivalent to:
a > (unsigned int) -1
The conversion of -1 to unsigned int makes the resulting value a huge unsigned int value and as a initial value is 0, the expression is evaluated to false (0).
Now if a is of type char or int, -1 is then not converted to unsigned int and so 0 > -1 is true (1) as expected.
Quote excerpted from ISO/IEC 9899:
If both of the operands have arithmetic type, the usual arithmetic conversions are
performed.
Several operators convert operand values from one type to another automatically.
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:
First, if the corresponding real type of either operand is long double(...)
Otherwise, if the corresponding real type of either operand is double(...)
Otherwise, if the corresponding real type of either operand is float(...)
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.
Otherwise, if both operands have signed integer types or both have unsigned
integer types(...)
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.
Basically, when you do an operation in C, the operation must be executed in a base at least as big as the greater operator.
So, assuming that your int is an int32, the operation:
uint32_t > int32_t
the operation must be executed in the base "uint32_t" or grater. In this case, it is being executed in the "uint32_t".
When you do:
uint8_t > int32_t
the operation is being executed in the base "int32_t" or greater.
Usually, when possible, the operation will be executed in the "int" base, as it is supposed to be faster than any other base.
So, if you do:
(int)unsigned char > int(-1)
, the condition will always be true.
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.