问题问,
令 int x = 1,找到 int y 的值,其中以下语句将返回 false:
(x < y) == (-x > -y)
我知道答案应该是 4 个字节长(8 个十六进制数字),但我不知道如何解决这个问题。
y
没有任何值使得表达式为假。如果我们编译这个:
int test(int y)
{
int x = 1;
return (x < y) == (-x > -y);
}
启用优化的 gcc 和 clang 都会生成以下代码:
test(int):
mov eax, 1
ret
任何其他认为聪明的答案很可能使用溢出,实际上是未定义的行为或误解了一些 C 基础知识。
实际上,
x
或 y
都没有值使得表达式为假:
int test(int x, int y)
{
return (x < y) == (-x > -y);
}
给出相同的:
test(int, int):
mov eax, 1
ret
似乎有些人忽略了编译器将表达式转换为
return 1
这一事实的含义和意义。这证明编译器已经明确证明不存在表达式为假的有效输入。否则就不会被允许做这个优化。
当 x 是有符号整数并且 x=1 时,找到一个值 y,这样 (x < y) == (-x > -y) 将为 false?
当
unsigned y = 0
时。
int main(void) {
int x = 1;
unsigned y = 0;
printf("%u\n", (x < y) == (-x > -y));
return 0;
}
输出
0
哎呀直到后来才看到“找到
int y
的值(十六进制)”。
将其发布为 wiki,因为它回答了标题问题,但在细节方面不允许。
答案是
INT_MIN == -INT_MIN
,我想你已经知道它是如何工作的了。
但是如果你想做一个实验并且对编译器优化感觉不好, 您可以使用
noclone
属性来防止编译器进行常量传播,
和 noinline
属性让 less()
是 main()
的黑盒子
#include <limits.h>
__attribute__ ((noclone, noinline))
int less (int x, int y) {
return x > y;
}
__attribute__ ((noclone, noinline))
int neg (int x) {
return -x;
}
int main(void) {
int x = 1, y = INT_MIN;
return less(x, y) == less(neg(y), neg(x));
}
如果
int
定义为32位补码值,则0x80000000
值将无法比较。原因是二补值的负数比正数多一个值。任何正值都可以转换为负值,但并非所有负值都可以转换为正值。
因此,对于上述值,
y
和-y
实际上是相同的值,第一次比较(x < y)
将产生“假”,其中(-x > -y)
将产生“真”,使整个表达式“假” .
但是,如果像 @bolov 的答案一样,编译器优化了该函数,则不会发生这种情况。