使用gcc的-fno-math-errno可能产生哪些副作用?

时间:2019-06-11 19:20:29

标签: c++ gcc g++

在编译代码时,使用此选项可大大提高速度。从手册页上可以看到该选项:

  

在调用执行的数学函数后不要设置“ errno”   一条指令,例如“ sqrt”

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

  

依赖IEEE例外进行数学错误处理的程序可能   想要在维护IEEE算术的同时使用此标志来提高速度   兼容性。

我不清楚这是什么意思,是c ++的IEEE例外标准或c ++的通用库(例如Eigen,Boost等)

本质上,我试图确定这是否是在我的代码中使用的“安全”选项,或者我应该从使用它的过程中了解哪些副作用。 previous answer说这可能会影响“线程局部变量”,但我不知道这意味着什么。

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

1 个答案:

答案 0 :(得分:3)

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

这些功能之一失败时,the global integer errno is set to a value that tells you why。显然,这会导致性能下降。

GCC表示,此标志禁用某些数学函数的此行为,从而以节省诊断实用程序和标准合规性的代价来加快程序运行速度。

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


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

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

糟糕!即使errno成功,我们也正在检查some_maths_function(42)。假设在此代码上方是对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);
}

当然,您遇到的bug几乎不是GCC的错,但这确实显示了启用此“优化”标志后程序的行为会有所不同。实际上,the documentation说:

  

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

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


变量errno必须是线程局部的(也就是说,程序中的每个线程实际上都有一个变量),否则在多线程程序中就没有用了。您可以研究“本地线程”一词,以获取有关此主题的更多信息。