gpt4 book ai didi

c++ - 如何在不执行的情况下捕获未定义的行为?

转载 作者:太空狗 更新时间:2023-10-29 19:52:32 25 4
gpt4 key购买 nike

在我的软件中,我在运行时使用用户的输入值并执行一些数学运算。为简单起见,请考虑以下示例:

int multiply(const int a, const int b)
{
if(a >= INT_MAX || B >= INT_MAX)
return 0;
else
return a*b;
}

我可以检查输入值是否大于限制,但如何检查结果是否超出限制? a = INT_MAX - 1b = 2 很有可能。由于输入完全有效,它将执行未定义的代码 makes my program meaningless .这意味着在此之后执行的任何代码都是随机的,最终可能会导致崩溃。那么在这种情况下我该如何保护我的程序呢?

最佳答案

这实际上取决于您在这种情况下实际想要做什么。

对于 longlong long(或 int64_t)为 64 位值且 int 是一个 32 位值,你可以这样做(我假设 long 在这里是 64 位):

long x = static_cast<long>(a) * b;
if (x > MAX_INT || x < MIN_INT)
return 0;
else
return static_cast<int>(x);

通过将一个值转换为 long,另一个值也必须进行转换。如果这会让你更快乐,你可以同时施放两者。这里的开销,高于普通的 32 位乘法,是现代 CPU 的几个时钟周期,您不太可能找到更安全、速度更快的解决方案。 [在某些编译器中,您可以向 if 添加属性,表示对于返回 x 的常见情况,不太可能鼓励分支预测“使其正确”]

显然,这不适用于类型与您可以处理的最大整数一样大的值(尽管您可以使用 float ,但它可能仍然有点不可靠,因为 float 的精度是不够 - 可以使用一些“安全裕度”来完成[例如,与小于 LONG_INT_MAX/2] 进行比较,如果您不需要整个整数范围。)不过这里的惩罚有点糟糕,尤其是 float 和整数之间的转换并不“令人愉快”。

另一种选择是使用“已知无效值”实际测试相关代码,只要其余代码“正常”即可。确保使用相关的编译器设置对此进行测试,因为更改编译器选项会改变行为。请注意,您的代码随后必须处理“当 65536 * 100000 为负数时我们要做什么”,而您的代码并未预期如此。也许添加如下内容:

 int x = a * b;
if (x < 0) return 0;

[当然,这只有在您不希望出现负面结果时才有效]

您还可以检查生成的汇编代码并了解实际处理器的架构 [这里的关键是了解“溢出会陷入”——在 x86、ARM、68K、29K 中默认情况下不会陷入。我认为 MIPS 有一个选项“溢出陷阱”],并确定它是否可能导致问题 [1],并添加类似

的内容
#if (defined(__X86__) || defined(__ARM__))
#error This code needs inspecting for correct behaviour
#endif
return a * b;

然而,这种方法的一个问题是,即使是代码或编译器版本中最细微的变化也可能会改变结果,因此将其与上面的测试方法结合起来很重要(并确保测试实际的生产代码,不是一些乱七八糟的小例子)。

[1] 未定义“未定义行为”允许 C 在具有整数数学溢出陷阱的处理器上“工作”,以及 a * b 溢出时的事实有符号值当然很难确定,除非你有一个定义的数学系统(二进制补码,一个补码,不同的符号位) - 所以为了避免在这些情况下“定义”确切的行为,C 标准说“它是未定义的” .这并不意味着它一定会变坏。

关于c++ - 如何在不执行的情况下捕获未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24339208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com