Why doesn't integer promotion happen in my case? - c

#include <stdio.h>
void main()
{
unsigned char a = 0xfb;
char b = 0xfb;
printf("case1 : %d, %d", a, b); // case1
char x=90, y=60, z=100, h;
h = x*y/z;
printf("\ncase2 : %d", h); // case2
int m = 32768, n = 65536, o = 2, i;
i = m*n/o;
printf("\ncase3 : %d", i); // case3
}
result
case1 : 251, -5
case2 : 54
case3 : -107341824
In case1, identifier b is compiled as -5, which is not syntax error thought char only accept -128~127 value. So, first question is identifier b is firstly saved as int data type by end of its translation?(When translation is end, b will be saved in char.)
In case2, x, y is promoted as int. So h has right result value. But in case3, m, n aren't promoted as unsigned int(maybe). Identifier I doesn't have ordinary value(2^30).
C99 says that
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int.
Being based on C99, value of h is natural, but dealing with m*n/o is overflowed. It's not natural because it's opposed to C99. This is my second query.

In case1, identifier b is compiled as -5, which is not syntax error
thought char only accept -128~127 value. So, first question is
identifier b is firstly saved as int data type by end of its
translation?(When translation is end, b will be saved in char.)
In case 1, the initializer for variable b, the constant 0xfb, represents a value of type int with value 251 (decimal). In the C abstract machine model, this value is converted to b's type (char) when the initializer runs, which for a block-scope variable is when execution reaches that declaration (not during translation). If indeed the range of char in your implementation is -128 - 127 then you have signed chars that cannot represent the initializer value, resulting in implementation-defined behavior.
So, again referencing the abstract machine model, nothing is stored in b at the end of translation. It is a block-scope variable, so it does not exist until execution reaches its declaration. The translated program does need somehow to store b's initial value, but C does not specify in what form it should do so. At no time during translation or execution does b contain a value of type int, however.
When the arguments to the printf call are evaluated, b's value is read and then converted to int (because it is a variadic argument). Arguably, then, it is ok to use a %d field to print it, but if you want to be certain to print the pre-conversion value then you should really use %hhd instead (though in your case, that will almost certainly print the same result).
In case2, x, y is promoted as int. So h has right result value.
More specifically, in case 2, the values of x, y, and z are promoted to int during evaluation of the expression x*y/z, and each operation produces an int result. The multiplication does not overflow the chosen type, int, and the overall result is in the range of type char, so the conversion to char applied upon assignment to h is unremarkable.
But in
case3, m, n aren't promoted as unsigned int(maybe). Identifier I
doesn't have ordinary value(2^30).
In case 3, m, n, and o already have type int, so they are not promoted, and the arithmetic expressions compute results of the same type (int). The result of sub-expression m*n is not in the range of type int, so undefined behavior ensues, pursuant to paragraph 6.5/5 of the Standard:
If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or
not in the range of representable values for its type), the behavior
is undefined.
It is true that
C99 [and C11] says that
If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int.
, but that is irrelevant here. It is part of the description of the of the "integer promotions", which apply to the operands of an expression, based on their types.
Being based on C99, value of h is natural, but dealing with m*n/o is
overflowed. It's not natural because it's opposed to C99. This is my
second query.
You seem to expect that the intermediate expression m*n will be evaluated to produce a result of type unsigned int, so that it does not overflow, but this is not supported by the standard. The usual arithmetic conversions, including the integer promotions, are based only on the characteristics of operand types, including their signedness and value ranges. Operators that are subject to the usual arithmetic conversions, including *, use them to determine a common type for all operands and the result.
Your m and n already being the same type, and that type being int, no conversions / promotions apply. The result of the multiplication would also be an int if m and n's values were not such that their product (as an int) is undefined. In fact, however, the operation overflows type int, yielding undefined behavior.

In case 1, initializing a char, which is signed on your platform, with the value 0xfb, greater than CHAR_MAX, is not a syntax error. The effect is implementation defined and unsurprisingly 0xfb is converted to the value -5 which has the same 8-bit pattern. a and b are promoted to int when passed as variable arguments to printf because this is the specified behavior in such a case.
In case 2, x, y and z are promoted to int, because on your platform type int can represent all values of type char. The computation is performed with int arithmetic, producing a result of 54, which is in the range of type char, so can be stored into h without a problem. h is promoted to int when passed to printf as above.
In case 3, m and n are not promoted because they have type int already. The promotion rules apply to each operand, not to the result of the operation as if it was performed with arbitrary precision: m*n is performed with int arithmetic and overflows on your platform where int is presumably 32 bits wide. The behavior is undefined. It so happens that the result is -2147483648 so dividing it by 2 yields -107341824 but this is not guaranteed by the C Standard.
For the computation to be performed accurately, at least m or n must have a larger type or be cast as such: i = (unsigned)m * n / o; would produce 107341824 on your platform, but beware that type int might have fewer than 32 bits. For a portable expression, you would need to use type unsigned long, which is specified as having at least 32 value bits, for both the cast and the type of i.
Finally, main should be defined as int main() or int main(void) or int main(int argc, char *argv[]) or a compatible prototype. void main() is incorrect.

#include <stdio.h>
int main()
{
unsigned char a = 0xfb;
char b = 0xfb;
printf("case1 : %d, %d", a, b); // case1
char x=90, y=60, z=100, h;
h = x*y/z;
printf("\ncase2 : %d", h); // case2
unsigned long long int m = 32768, n = 65536, o = 2,i;
i = m*n/o;
printf("\ncase3 : %llu", i); // case3
}
in this type you can get answer [0, +18,446,744,073,709,551,615] range

Related

Problems casting a double into an unsigned char

Why does casting a double 728.3 to an unsigned char produce zero? 728 is 0x2D8, so shouldn't w be 0xD8 (216)?
int w = (unsigned char)728.3;
int x = (int)728.3;
int y = (int)(unsigned char)728.3;
int z = (unsigned char)(int)728.3;
printf( "%i %i %i %i", w, x, y, z );
// prints 0 728 0 216
From the C standard 6.3.1.4p1:
When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero). If the value of the integral part cannot be represented by the integer type, the behavior is undefined.
So, unless you have >=10 bit unsigned char, your code invokes undefined behaviour.
Note that the cast explicitly tells the compiler you know what you are doing, thus suppresses a warning.
Supposing that unsigned char has 8 value bits, as is nearly (but not completely) certain for your implementation, the behavior of converting the double value 728.3 to type unsigned char is undefined, as specified by paragraph 6.3.1.4/1 of the standard:
When a finite value of real floating type is converted to an integer
type other than _Bool, the fractional part is discarded (i.e., the
value is truncated toward zero). If the value of the integral part
cannot be represented by the integer type, the behavior is undefined.
This applies to both your w and your y. It does not apply to your x, and the rules covering conversions between integer values (i.e. your z) are different.
Basically, then, there is no answer at the C level for why you see the specific results you do, nor for why I see different ones when I run your code. The behavior is undefined; I can be thankful that it did not turn out to be an outpouring of nasal demons.

Confusion about sizeof operator in C

I'm confused about sizeof operator in C.
#include <stdio.h>
int main(void)
{
char num1=1, num2=2, result;
result = num1 + num2;
printf("Size of result: %d \n",sizeof result);
printf("Size of result: %d \n",sizeof(num1+num2));
}
The results are 1 and 4 respectively. Why does this happen?
TL;DR answer:
sizeof result is same as sizeof(char).
sizeof(num1+ num2) is same as sizeof (int) why?
In your case, they produce 1 (guaranteed by standard) and 4 (may vary), respectively.
That said, sizeof produces a result of type size_t, so you should %zu format specifier to print the value.
Why:
First, for the addition operator +, quoting C11, chapter §6.5.6
If both operands have arithmetic type, the usual arithmetic conversions are performed on
them.
Regarding usual arithmetic conversions, §6.3.1.8/p1
[....] Otherwise, the integer promotions are performed on both operands.[...]
and then from §6.3.1.1,/p2,
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.
So, sizeof(num1+num2) is the same as sizeof(int).
result is of char type, therefore sizeof is giving 1 while num1+num2 promoted to int type and therefore it gives 4 (size of int).
Note that when an arithmetic operation is performed on a type smaller than that of int and all of it's value can be represented by int then result will be promoted to int type.
num1 + num2 is becoming integer and hence the output is 4 whereas result is char which outputs 1.
You can refer this article Integer Promotion:
If an int can represent all values of the original type, 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.
the size of one char is 1byte, a char can hold values up to 127(unsigned up to 255).
when you say something like (a + b) a temporary variable is created and used to add a to b, because a and b can hold only 127, they are promoted by the compiler to be an int, just to be sure.
which is logical because if a = 100 and b = 100, the user would like to see 200 when he adds them and not 73 (which is the result of an overflow).

sizeof an integer expression in C

To my semi-surprise with Xcode compiling C (gnu11)
#include <stdio.h>
int main(int argc,char**argv)
{
short s = 1;
printf( "%zd %zd %zd\n", sizeof(s), sizeof(s*s), sizeof(s?s:s));
return 0;
}
Produces the output
2 4 4
I was expecting
2 2 2
or possibly
2 4 2
Why is this?
I recalled from K&R that any integer expression smaller than an int is promoted to int. I found this in Standard (C89):
3.2.1.1 Characters and integers
A char, a short int, or an int bit-field, or their signed or
unsigned varieties, or an object that has enumeration type, may be
used in an expression wherever an int or unsigned int may be used. If
an int can represent all values of the original type, the value is
converted to an int;
The surprise is s?s:s because all reference I could find say the resulting type is an lvalue but that's just C++. C treats it as an rvalue. As expected then, C++'s output is:
2 4 2
Even if the expression is an rvalue. An unexpected difference between C and C++.
This is because the latter two sizeof operands contain operators. In C, types narrower than int are promoted to int before the operation is performed. So s * s is an int multiplied with an int, yielding an int.
Similarly for short ? short : short getting promoted to int ? int : int.
According to C11§6.5.15/5:
If both the second and third operands have arithmetic type, the result type that would be determined by the usual arithmetic conversions, were they applied to those two operands, is the type of the result. [...]
In your case, the result is equal to sizeof(int) because the 'usual arithmetic conversions' promote the shorts to ints. Same as with sizeof(s*s).

unsigned int data types in c

Please help me in differentiating these codes in C:
Code 1:
#include<stdio.h>
#include <stdint.h>
uint8_t fb(int a)
{
return -3;
}
int main()
{
int a = fb(-3);
printf("%d",a);
return 0;
}
Code 2:
#include<stdio.h>
unsigned int fb(int a)
{
return -3;
}
int main()
{
int a = fb(-3);
printf("%d",a);
return 0;
}
The problem is the the first code returns 253 as expected but the second code returns -3 which is unexpected as return type is unsigned. Please help me how this is possible?
I have used mingw gcc compiler.
In the first program,
When the function returns, int -3 (FFFFFFFD) is cast to uint8_t is 253 (FD). The higher order bytes are dropped so it fits.
When the assignment is performed, uint8_t 253 (FD) is cast to int by sign extension to 253 (000000FD).
In the second program,
When the function returns, int -3 (FFFFFFFD) cast to unsigned int 4294967293 (FFFFFFFD). No bytes needed to be dropped.
When the assignment is performed, unsigned int 4294967293 (FFFFFFFD) cast to int is -3 (FFFFFFFD).
Notes:
Assumes 32-bit ints, but it's a similar story with 64-bit ints.
This is an explanation of what happens for you; it isn't necessarily what the C spec calls to happen.
The conversion from signed to unsigned will follow the rules laid out in section 6.3.1.3 Signed and unsigned integers of the draft C99 standard which says:
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.49)
So this means that -3 will be converted to by adding UMAX +1 to the value. In the case of uint8_t this is a relatively small value 253 which fits into a singed int and therefore is converted to signed int without issue.
In your second case with the return value of unsigned int, we will end up with a rather large value upon conversion, actually std::numeric_limits<unsigned int>::max() + 1 - 3. Which will not fit into an signed int this is overflow and is thus undefined behavior as per section 6.5 paragraph 5 which says:
If an exceptional condition occurs during the evaluation of an
expression (that is, if the result is not mathematically defined or
not in the range of representable values for its type), the behavior
is undefined.
unsigned int should be printed as %u instead of %d
The rule for conversion from integral type to an unsigned integral type is simple:
Add/Subtact (Maximum value of target type + 1) as often as needed to fit.
The rule for conversion from integral type to signd integral type is simpler still:
Preserve the value, if out-of-range the conversion is undefined.
Most modern implementations (all on windows platform) define it to add/subtract same constant as for corresponding unsigned type until it fits though.
Using those rules, the conversion on return from fb() in the first example is value-preserving and ok:
-3 -> 256-3 = 253 -> 253
The return in the second example is out-of-range and thus undefined behavior, though normally:
-3 -> 2CHAR_BIT*sizeof(int)-3 -> -3
Bonus facts:
Passing a variadic function a signed/unsigned type where the corresponding other one was expected is allowed, though the raw value cannot be converted and will just be assumed to be of the indicated type.
CHAR_BIT is a preprocessor constant giving the number of bits in a byte.
sizeof is an operator giving the number of bytes in a type / variable.

Comparison operation on unsigned and signed integers

See this code snippet
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
This gives the output: a is SMALL: 1001
I don't understand what's happening here. How does the > operator work here? Why is "a" smaller than "b"? If it is indeed smaller, why do i get a positive number (1001) as the difference?
Binary operations between different integral types are performed within a "common" type defined by so called usual arithmetic conversions (see the language specification, 6.3.1.8). In your case the "common" type is unsigned int. This means that int operand (your b) will get converted to unsigned int before the comparison, as well as for the purpose of performing subtraction.
When -1 is converted to unsigned int the result is the maximal possible unsigned int value (same as UINT_MAX). Needless to say, it is going to be greater than your unsigned 1000 value, meaning that a > b is indeed false and a is indeed small compared to (unsigned) b. The if in your code should resolve to else branch, which is what you observed in your experiment.
The same conversion rules apply to subtraction. Your a-b is really interpreted as a - (unsigned) b and the result has type unsigned int. Such value cannot be printed with %d format specifier, since %d only works with signed values. Your attempt to print it with %d results in undefined behavior, so the value that you see printed (even though it has a logical deterministic explanation in practice) is completely meaningless from the point of view of C language.
Edit: Actually, I could be wrong about the undefined behavior part. According to C language specification, the common part of the range of the corresponding signed and unsigned integer type shall have identical representation (implying, according to the footnote 31, "interchangeability as arguments to functions"). So, the result of a - b expression is unsigned 1001 as described above, and unless I'm missing something, it is legal to print this specific unsigned value with %d specifier, since it falls within the positive range of int. Printing (unsigned) INT_MAX + 1 with %d would be undefined, but 1001u is fine.
On a typical implementation where int is 32-bit, -1 when converted to an unsigned int is 4,294,967,295 which is indeed ≥ 1000.
Even if you treat the subtraction in an unsigned world, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 which is what you get.
That's why gcc will spit a warning when you compare unsigned with signed. (If you don't see a warning, pass the -Wsign-compare flag.)
You are doing unsigned comparison, i.e. comparing 1000 to 2^32 - 1.
The output is signed because of %d in printf.
N.B. sometimes the behavior when you mix signed and unsigned operands is compiler-specific. I think it's best to avoid them and do casts when in doubt.
#include<stdio.h>
int main()
{
int a = 1000;
signed int b = -1, c = -2;
printf("%d",(unsigned int)b);
printf("%d\n",(unsigned int)c);
printf("%d\n",(unsigned int)a);
if(1000>-1){
printf("\ntrue");
}
else
printf("\nfalse");
return 0;
}
For this you need to understand the precedence of operators
Relational Operators works left to right ...
so when it comes
if(1000>-1)
then first of all it will change -1 to unsigned integer because int is by default treated as unsigned number and it range it greater than the signed number
-1 will change into the unsigned number ,it changes into a very big number
Find a easy way to compare, maybe useful when you can not get rid of unsigned declaration, (for example, [NSArray count]), just force the "unsigned int" to an "int".
Please correct me if I am wrong.
if (((int)a)>b) {
....
}
The hardware is designed to compare signed to signed and unsigned to unsigned.
If you want the arithmetic result, convert the unsigned value to a larger signed type first. Otherwise the compiler wil assume that the comparison is really between unsigned values.
And -1 is represented as 1111..1111, so it a very big quantity ... The biggest ... When interpreted as unsigned.
while comparing a>b where a is unsigned int type and b is int type, b is type casted to unsigned int so, signed int value -1 is converted into MAX value of unsigned**(range: 0 to (2^32)-1 )**
Thus, a>b i.e., (1000>4294967296) becomes false. Hence else loop printf("a is SMALL! %d\n", a-b); executed.

Resources