这将是困难的。GCC<cmath>
标头仅包含<math.h>
、#undefs
其宏(以防万一)并将 C++ 函数定义为内联函数,这些函数使用<math.h>
. 大多数函数实际上是指编译器内置函数:例如,std::abs
是使用__builtin_abs
而不是定义的::abs
。
由于<cmath>
和您的“错误程序”都在同一个翻译单元中,因此很难看出如何分离可见性:如何<cmath>
允许内联函数使用<math.h>
东西,而您的代码不会。
嗯,有以下方法:<cmath>
必须重写以提供它自己的本地范围声明,用于它需要的任何内容,<math.h>
而不是实际包含该标头。
我们可以做的是准备一个头文件,它重新声明我们不想要的函数,并带有__attribute__ ((deprecated))
:
// put the following and lots of others like it in a header:
extern "C" int abs(int) throw () __attribute__ ((deprecated));
#include <cmath>
#include <cstdlib>
#include <iostream>
int main() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return 0;
}
}
现在:
$ g++ -Wall buggy.cc
buggy.cc: In function ‘int main()’:
buggy.cc:9:7: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
if (abs(-0.75) != 0.75) {
^~~
In file included from /usr/include/c++/6/cstdlib:75:0,
from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
^~~
buggy.cc:9:16: warning: ‘int abs(int)’ is deprecated [-Wdeprecated-declarations]
if (abs(-0.75) != 0.75) {
^
In file included from /usr/include/c++/6/cstdlib:75:0,
from buggy.cc:4:
/usr/include/stdlib.h:735:12: note: declared here
extern int abs (int __x) __THROW __attribute__ ((__const__)) __wur;
^~~
链接器警告会更简单。我试过了;问题是这个测试程序实际上并没有生成一个外部引用abs
(即使有一个#undef abs
in <cmath>
)。该调用被内联,因此避开了链接器警告。
更新:
跟进 DanielH 的评论,我想出了一个允许std::abs
但阻止的技巧的改进abs
:
#include <cmath>
#include <cstdlib>
#include <iostream>
namespace proj {
// shadowing declaration
int abs(int) __attribute__ ((deprecated));
int fun() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return std::abs(-1); // must be allowed
}
}
}
int main() {
return proj::fun();
}
可以使用简单的命名空间。另外,我们不需要deprecated
属性;我们可以只声明abs
一个不兼容的函数,或者完全声明一个非函数标识符:
#include <cmath>
#include <cstdlib>
#include <iostream>
namespace proj {
// shadowing declaration
class abs;
int fun() {
if (abs(-0.75) != 0.75) {
std::cout << "Math is broken!\n";
return 1;
} else {
return std::abs(-1); // must be allowed
}
}
}
int main() {
return proj::fun();
}
$ g++ -std=c++98 -Wall buggy.cc -o buggy
buggy.cc: In function ‘int proj::fun()’:
buggy.cc:10:18: error: invalid use of incomplete type ‘class proj::abs’
if (abs(-0.75) != 0.75) {
^
buggy.cc:7:9: note: forward declaration of ‘class proj::abs’
class abs;
^~~
buggy.cc:16:3: warning: control reaches end of non-void function [-Wreturn-type]
}
^
使用这种方法,我们只需要一个名称列表并将它们转储到一些提供此功能的标题中:
int abs, fabs, ...; // shadow all of these as non-functions
我-stdc++98
在g++
命令行中使用来强调这只是在工作的老式 C++namespace
语义。