标题基本上说明了一切。我的朋友给了我这个挑战,他在他正在做的一些 CTF 中解决了这个挑战。我已经考虑了一段时间,无法弄清楚。此外, INFINITY 不是一个有效的答案。谢谢。
3 回答
在 C 中发生这种情况的唯一方法是:
x
是无穷大(+∞ 或 -∞)(等效地,HUGE_VAL
或-HUGE_VAL
在不支持无穷大的实现中)。x
是一个 NaN,C 实现对 NaN 使用非 IEEE-754 行为。x
与浮点表示中的无穷大相邻,并且使用了合适的有向舍入模式。x+1
和x*2
溢出以及 C 标准未定义的结果行为恰好将比较报告为真。x
是未初始化的,因此是不确定的,并且在 in 的两个外观中采用不同的值,x
因此x+1 == x
比较为真,并且在x*2 == x
类似地采用不同的值或采用零值。x
未初始化并具有自动存储持续时间且其地址未被占用,因此 C 标准未定义该行为,并且结果行为恰好将比较报告为真。
证明:
除了无穷大之外,这些陈述在实数中在数学上是错误的,因此这不能由实数行为引起。所以它一定是由一些非实数行为引起的,例如溢出、换行、舍入、不确定的值(在每次使用对象时可能不同)或未初始化的值。由于*
被限制为具有算术操作数,我们只需要考虑算术类型。(在 C++ 中,可以定义一个类来进行比较。)
对于有符号整数,具有完全定义值的非实数行为仅在溢出时才会发生+
,*
因此这是可能的。
对于无符号整数,具有完全定义值的非实数行为+
仅*
在有回绕时才会发生。然后,通过模M包裹,对于某个整数k,我们将有x +1 = x + kM,因此 1 = kM ,这对于包裹中使用的任何M都是不可能的。
对于该_Bool
类型,对可能值的详尽测试会消除它们。
对于浮点数,具有完全定义值的非实数行为仅发生在舍入、下溢+
和*
溢出以及 NaN 的情况下。NaN 从不按照 IEEE-754 规则进行比较,因此它们不能满足这一点,除非 C 标准不要求符合 IEEE-754,因此实现可以选择使比较为真。
x*2
不会下溢,因为它会增加幅度。x+1
可以使指数范围小于精度的反常浮点格式下溢,但这不会产生x+1 == x
. x+1 == x
可以通过四舍五入足够大来满足x
,但x*2
必须产生除 之外的值x
。
留下溢出。如果x
是最大可表示有限数(因此最大可表示数小于无穷大),并且舍入模式是向下(向 -∞)或向零,x+1
则将产生x
并且x*2
将产生x
,因此比较结果为真。类似地,最大负可表示有限数将满足向上舍入(向+∞)或向零舍入的比较。
等式将适用于double x = HUGE_VAL;
。从 C99 开始,引用cppreference.com:
,和宏扩展为正浮点常量表达式
HUGE_VALF
,它们比较等于浮点函数和运算符在溢出情况下返回的值HUGE_VAL
HUGE_VALL
示例代码:
#include <math.h>
#include <stdio.h>
int main() {
double x = HUGE_VAL;
printf("%d %d\n", x + 1 == x, 2 * x == x);
return 0;
}
输出:
1 1
解决x
使用 C 预处理器的问题:
#include <stdio.h>
int main() {
#define x 1,1
if (x + 1 == x)
printf("x + 1 == x is true\n");
if (x * 2 == x)
printf("x * 2 == x is true\n");
printf("x = %d\n", x);
printf("x + 1 = %d\n", x + 1);
printf("x * 2 = %d\n", x * 2);
return 0;
}
输出(省略警告:):
x + 1 == x is true
x * 2 == x is true
x = 1
x + 1 = 1
x * 2 = 1