假设我有一个来自外部来源的变量i
:
int i = get_i();
假设i
是INT_MIN
和两个补码表示,-i
是否未定义?
答案 0 :(得分:6)
这取决于平台。 C支持负数的三种表示(参见C99标准的section 6.2.6.2):
使用补码和符号和幅度,-INT_MIN
被定义(并且等于INT_MAX
)。使用二进制补码时,它取决于符号位1和所有值位零的值是陷阱表示还是正常值。如果它是正常值,-INT_MIN
溢出,导致未定义的行为(请参阅C99标准的section 6.5)。如果它是陷阱表示,-INT_MIN
等于INT_MAX
。
也就是说,大多数现代平台使用两个补码而没有陷阱表示,因此-INT_MIN
通常会导致未定义的行为。
答案 1 :(得分:2)
平台可以选择定义行为,但C标准不要求他们保证任何相关内容。虽然历史上微型计算机编译器的行为相对一致,但-INT_MIN会产生INT_MIN,或者在某些情况下表现的行为类似于大于INT_MAX的值,因此将追溯更改为更为时尚任何被否定的价值。因此,给出:
int wowzers(int x)
{
if (x != INT_MIN) printf("Not int min!");
return -x;
}
超现代编译器可以使用表达式-x来确定x是否可以 在执行先前的比较时,它等于INT_MIN,并且 因此可以无条件地执行printf。
顺便说一句,gcc 8.2将使用否定INT_MIN的UB-ness来优化"以下
int qq,rr;
void test(unsigned short q)
{
for (int i=0; i<=q; i++)
{
qq=-2147483647-i;
rr=qq;
rr=-rr;
}
}
代码无条件地将-2147483647存储到qq
和2147483647到rr
。删除rr=-rr
行将使代码存储为-2147483647或-2147483648 qq
和rr
,具体取决于q
是否为零。
答案 2 :(得分:0)
否定INT_MIN未定义的行为?
是的,当INT_MIN < -INT_MAX
-非常很常见(2的补码)时。这是整数溢出。
int i = get_i();
#if INT_MIN < -INT_MAX
if (i == INT_MIN) {
fprintf(stderr, "Houston, we have a problem\n";
// Maybe return or exit here.
}
#endif
int j = -i;