我想禁止在我拥有的代码库中使用iostream(出于各种原因)。有没有办法可以检查符号文件或强制编译器在使用该API时发出错误?
答案 0 :(得分:36)
一种简单的方法是提供一个虚拟iostream
实现,除了抛出编译时错误之外什么都不做。
以下示例假定使用GCC工具链 - 我想这个过程与其他编译器类似。
首先,创建您的虚拟iostream文件:
#error 'Use of iostream is prohibited'
用于演示的一些虚拟应用程序代码:
#include <iostream>
int main (int argc, char** argv) {
std::cout << "foo!";
return 0;
}
编译如下(假设虚拟iostream
和main.cpp
在工作目录中):
g++ -I. main.cpp
编译失败,出现以下错误:
In file included from main.cpp:2:0:
./iostream:1:2: error: #error 'Use of iostream is prohibited'
main.cpp: In function 'int main(int, char**)':
main.cpp:4:2: error: 'cout' is not a member of 'std'
添加了奖励:通常在该文件中声明的符号(例如此处为cout
)未定义,因此也会在编译器输出中标记。因此,您还可以准确地指出您使用禁用API的位置。
更新: Visual C ++ 2012的说明。
正如@RaymondChen在下面的评论中指出的那样,针对Visual C ++定制的解决方案可能对OP更有用。因此,下面概述了我在Visual C ++ 2012下实现与上述相同的过程。
首先,使用上面的C ++代码创建一个新的控制台项目。还要创建我上面描述的虚拟iostream头,并将其放在一个易于查找的目录中(我把它放在主项目源目录中)。
现在,在解决方案资源管理器中,右键单击项目节点,然后从下拉列表中选择“属性”。在出现的对话框中,从左侧的树中选择“VC ++目录”。将包含虚拟iostream文件的目录添加到右侧显示的包含目录列表中,并使用分号与其他目录分隔:
在这里,我的项目名为TestApp1,我只是将其主目录添加到已存在的$(IncludePath)
。请注意,前置而不是附加很重要 - 列表中目录的顺序决定了搜索顺序,因此如果在自定义目录之前出现 {em>},系统标头将被使用优先于您的虚拟标题 - 不是您想要的。
单击“确定”,然后重建项目。
对我来说,这样做导致VC ++控制台出现以下错误(为简洁起见略有编辑):
$(IncludePath)
请注意,IntelliSense还会选择(现在)非法使用error C1189: #error : 'Use of iostream is prohibited'
IntelliSense: #error directive: 'Use of iostream is prohibited'
IntelliSense: namespace "std" has no member "cout"
- 它会在编辑器中突出显示错误标记。
答案 1 :(得分:7)
这是一个讨厌的黑客,但它应该有用。
C标准(以及C ++标准)允许#include
指令中的预处理程序令牌。这也称为“计算包含”。
因此,在makefile中添加-Diostream
到CFLAGS
之类的东西(或IDE项目设置中的编译器选项),如果有人试图使用iostream,则应该可靠地破坏构建。
当然,对于空宏,错误消息不会提供很多信息,但您可以改为使用-Diostream=DUDE_DONT_USE_IOSTREAM
之类的内容,它会显示如下错误:DUDE_DONT_USE_IOSTREAM: file not found
。
如果你以后改变主意,这也是你可以在没有太多麻烦的情况下再次关闭的事情。只需删除构建选项。
答案 2 :(得分:5)
您检查符号文件的想法是可行且非常现实的。 virtual ~ios_base();
是一种单一的方法,所有流都将继承,并且由于它是虚拟和非平凡的,因此无法轻松地内联。因此,它在目标文件中的存在是IOstream使用的一个非常强烈的指示。
答案 3 :(得分:0)
除了Mac提到的编译器辅助方法,您还可以使用通用搜索功能。例如(我假设zsh shell - 对于bash没有**
,而在Windows上你需要找到如何使用Powershell做到这一点):
# Find all mentioning on `iostream` `cin` in all files ending in cc in all subdirectories of current directory
grep iostream **/*.c
grep cin **/*.cc
如果您不想/不能使用命令行,您可以使用自己喜欢的编辑器搜索不需要的符号。
我通常将两种方法结合起来:
objdump
或类似的(取决于平台)并观察导入的符号(如果您没有使用iostream静态链接某些内容,则此方法有效。)答案 4 :(得分:-12)
不,一点也不。对于非常有限的子集,您可以提供自己的定义,从而导致链接器在重复项上出错。但这将是非常未定义的行为。很好的部分是不易受此影响的模板。如果没有删除iostream标题或使用像Clang这样的编译器并修改源代码这样的重大事情,那么你真的无能为力。