使用 gcc 的 -fno-math-errno 可能有什么副作用?

What are the possible side-effects of using gcc's -fno-math-errno?

本文关键字:什么 副作用 可能有 -fno-math-errno gcc 使用      更新时间:2023-10-16

在编译代码时,使用此选项可以大大加快速度。 在手册页中,它说此选项:

调用执行的数学函数后不要设置"errno" 使用单个指令,例如"sqrt">

我不清楚"errno"是什么,以及如何在其他地方使用它(这与程序的退出代码相同吗?此外,手册页说:

依赖于IEEE异常进行数学错误处理的程序可能会 希望在保持 IEEE 算术的同时使用此标志来提高速度 兼容性。

我不清楚这意味着什么,是 c++ 的 IEEE 例外标准还是 c++ 的通用库(例如 Eigen、Boost 等)。

从本质上讲,我正在尝试确定这是否是在我的代码中使用的"安全"选项,或者我应该从它的使用中注意哪些副作用。之前的答案说这可能会影响"线程局部变量",但我不知道这意味着什么。

编辑:我的代码是一个简单的一次性程序代码来处理科学问题。它不会成为需要复杂错误处理的深度嵌入式系统的一部分。但是,代码不能以微妙、无声的方式失败。

C引入了单个errno或"错误号"的概念,可用于确定某些标准函数(包括数学函数)无法履行其职责的确切原因。POSIX扩展了errno,C++11也获得了其中一些扩展。

当其中一个函数失败时,全局整数errno将设置为告诉您原因的值。显然,这会导致性能损失。

GCC 说这个标志禁用了某些数学函数的这种行为,以诊断实用程序和标准合规性为代价加速了你的程序。

如果您已经没有观察到任何受影响的功能何时失败errno,并且您可能没有,因为您从未听说过它,那么您不会丢失任何功能。如果您正在编写一个非常有时间限制的程序,或者失败的特定原因并不决定您的代码下一步做什么,则可能就是这种情况。(但是,我建议更广泛地研究错误检查,以确保您的代码尽可能健壮。


但是,如果您有错误,您可能会意外观察到副作用。想象一下,如果您正在执行以下操作:

std::some_maths_function(42);
if (errno == ERANGE)
exit(-1);

哎呀!即使some_maths_function(42)成功,我们也在检查errno。假设上面的代码是对std::some_other_maths_function(999)的调用,该调用通常会失败并导致errno设置为EDOM。这掩盖了上面代码中的错误。

现在打开编译器标志。如果some_other_maths_function是不再设置errno的函数之一,您的错误将被揭开,并且您可能需要一些时间才能意识到您应该编写更多类似以下内容的内容:

if (std::some_maths_function(42) == -1)
{
if (errno == RANGE)
exit(-1);
}

当然,您遇到错误并不是GCC的错,但这确实显示了启用此"优化"标志后程序的行为有何不同。事实上,文件说:

任何 -O 选项都不会打开此选项,因为它可能导致依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序输出不正确。但是,它可能会为不需要这些规范保证的程序生成更快的代码。

换句话说,此标志将您送出书外。但这可能是值得的。


变量errno必须是线程本地的(也就是说,程序中每个线程实际上都有一个),否则它在多线程程序中将毫无用处。您可以研究术语"线程本地"以获取有关此主题的更多信息。

请注意,GCC 也可能禁用非数学函数的 errno,例如在使用 -fno-math-errno 时malloc。[0]

[0] -fno-math-errno 导致 GCC 认为 malloc 没有设置 errno