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 char
s 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.
m
andn
are already defined asint
. Thus, fori = m * n / o
you are simply seeing integer overflow. – Adrian Molem * n
exceeds the storage size forint
(by one), the intermediate result cannot be represented byint
. Why is unsigned integer overflow defined behavior but signed integer overflow isn't? – David C. Rankin