我的团队正在编写要为Windows(使用VS2015
)和Android(使用GCC 4.9
调用的QtCreator
)编译的代码。
我们发现Android二进制文件在abs
函数中存在问题。
double a = 1.0;
double b = 0.5;
std::cout << abs( a - b ) << std::endl;
std::cout << std::abs( a - b ) << std::endl;
显示器:
1
0.5
这是一个已知问题,发现此主题(以及其他): Strange bug in usage of abs() I encountered recently
我们使用abs
的地方很多,我会用std::abs
替换它们。精细。 但是如何防止将来再次使用abs
?
找到这个主题:Avoiding compiler issues with abs(),但它没有帮助。
我无法将所有警告视为错误(-Werror -Wall),因为g ++比MSVC更不宽容。即使我们努力在MSVC上使用0警告进行编译,我们仍然会使用g ++获得大量的警告(其中可能有一个关于abs被严重使用)并且我们在历史上忽略它们。修复它们会让我们付出太多努力。
答案 0 :(得分:3)
您是否可以在中央位置设置强制编译器标志(常见的cmake包含或您使用的其他任何构建系统)?如果是这样,您可以创建John所指示的头文件,并添加一个编译标志,该标志将包含任何编译单元开头的文件:
MSVC:/ FI&lt; path_to_file&gt;
GCC: - include&lt; path_to_file&gt;
Clang:与GCC相同
答案 1 :(得分:2)
你有一个基本包含在所有内容中的头文件吗?某种基本原则的持有者?如果是这样,你可以把它放在那里:
extern void NeverDefined();
inline int abs(int a) {
NeverDefined();
return a;
} // abs(int)
如果您在NeverDefined
上遇到链接器错误,您就会知道存在问题!
通常情况下,我根本不会定义有问题的函数,但由于它是一个库函数,我必须有第二级。
实际上:不要打扰头文件(标准定义就足够了)。使用上面的代码(无abs.cc
)编写您自己的inline
,它将取代库定义。
当然,如果原始文件标记了函数inline
,这将无效 - 在这种情况下,您始终可以编辑原始定义...
答案 2 :(得分:1)
正如你问题中相同的链接答案所示:
<math.h>
负责abs(int)
<cmath>
负责std::abs(double)
如果你有一个最顶层的头文件,那么只需将方法放在下面:
template<typename T> void abs (T);
因此,只要找到abs
,就会为其void
报告编译器错误作为返回值。此外,此功能未实现,至少会产生链接器错误
此编译器错误可用于将此abs()
替换为std::abs()
。对于无害的abs(int)
,预计不会产生任何错误,因为它在<math.h>
中可用。
假设您没有在所有源文件中包含任何头文件,那么作为一次练习,您可能希望将#include<math.h>
的每个文本替换为#include<cmath>
。但是,在所有情况下都不能完全证明这一点。例如:
double my_abs () {
using std::abs;
return abs(x - y);
}
因此,最好在所有源文件中都有一个公共实用程序头文件作为练习。让它为空。