问题
It seems clear that the following code invokes undefined behavior because of arithmetic overflow:
#include <limits.h>
int test(void) {
int i = INT_MAX;
i++; /* undefined behavior */
return i;
}
But what about signed types smaller than int
such as short
or signed char
? (by smaller, I assume SCHAR_MAX < INT_MAX
and SHRT_MAX < INT_MAX
respectively).
Which of the functions below invoke undefined behavior and why?
signed char test2(void) {
signed char i = SCHAR_MAX;
i = i + 1; /* implementation defined */
return i;
}
signed char test3(void) {
signed char i = SCHAR_MAX;
i += 1; /* undefined behavior or implementation defined? */
return i;
}
signed char test4(void) {
signed char i = SCHAR_MAX;
i++; /* undefined behavior or implementation defined? */
return i;
}
signed char test5(void) {
signed char i = SCHAR_MAX;
++i; /* undefined behavior or implementation defined? */
return i;
}
Please provide references from or quote the C Standard to support your reasoning.
回答1:
It would be logical for the +=
and similar operators to operate directly on values of the destination type, and on many implementations that is in fact what they do. The Standard, however, requires that the operator behave as though the value of the destination undergoes any applicable standard and balancing promotions, then processes the specified operation, and then gets converted back to the destination type.
Consequently, if s
and u
are signed and unsigned 16-bit variables, and int
is 32 bits, then s*=s;
will be defined for all values of s
[if the result exceeds 32767, it must either yield an implementation-defined value or raise an implementation-defined signal; most implementations would have to go out of their way to do anything other than two's-complement reduction]. On the other hand, u*=u;
will only be guaranteed to wrap mod 65536 for values of u
up to 46340; for larger values, it will invoke Undefined Behavior.
回答2:
The following code does cause and overflow and thus undefined behavior:
signed char i = SCHAR_MAX;
i++;
The operator postfix ++ does not perform integer promotions or usual arithmetic conversions1. The operator simply adds one to the value of the operand2. The operations overflows.
A clear distinction comes from the wording of the unary arithmetic operators: +
, -
, ~
, for which the wording clearly says that the operand is promoted3. But for the postfix ++
operator the wording doesn't say that the operator is promoted4.
Clearly the postfix ++ operator does not promote the operand.
1 (Quoted from: ISO/IEC 9899:201x 6.3.1.1 Boolean, characters, and integers 2 58))
The integer promotions are applied only: as part of the usual arithmetic conversions, to certain
argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the
shift operators, as specified by their respective subclauses.
2 (Quoted from: ISO/IEC 9899:201x 6.5.2.4 Postfix increment and decrement operators 2)
As a side effect, the
value of the operand object is incremented (that is, the value 1 of the appropriate type is
added to it)
3 (Quoted from: ISO/IEC 9899:201x 6.5.3.3 Unary arithmetic operators 2)
The result of the unary + operator is the value of its (promoted) operand. The integer
promotions are performed on the operand, and the result has the promoted type.
4 (Quoted from: ISO/IEC 9899:201x 6.5.2.4 Postfix increment and decrement operators 2)
The result of the postfix ++ operator is the value of the operand.
来源:https://stackoverflow.com/questions/40343751/does-i-invoke-undefined-behavior-for-signed-types-smaller-than-int-in-case-of