如何确保没有代码使用API​​?

时间:2013-08-12 01:35:31

标签: c++

我想禁止在我拥有的代码库中使用iostream(出于各种原因)。有没有办法可以检查符号文件或强制编译器在使用该API时发出错误?

5 个答案:

答案 0 :(得分:36)

一种简单的方法是提供一个虚拟iostream实现,除了抛出编译时错误之外什么都不做。

以下示例假定使用GCC工具链 - 我想这个过程与其他编译器类似。

首先,创建您的虚拟iostream文件:

#error 'Use of iostream is prohibited'

用于演示的一些虚拟应用程序代码:

#include <iostream>

int main (int argc, char** argv) {
    std::cout << "foo!";
    return 0;
}

编译如下(假设虚拟iostreammain.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文件的目录添加到右侧显示的包含目录列表中,并使用分号与其他目录分隔:

Adding new path to include directories list

在这里,我的项目名为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中添加-DiostreamCFLAGS之类的东西(或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这样的编译器并修改源代码这样的重大事情,那么你真的无能为力。