16

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

4

5 回答 5

36

一个简单的方法是提供一个虚拟iostream实现,它只会抛出一个编译时错误。

下面的例子假设一个 GCC 工具链——我想这个过程与其他编译器类似。

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

#error 'Use of iostream is prohibited'

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

#include <iostream>

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

编译如下(假设 dummyiostream并且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)已经存在的目录中。请注意,添加而不是附加很重要 - 列表中目录的顺序决定了搜索顺序,因此如果$(IncludePath)出现您的自定义目录之前,系统标题将优先使用您的虚拟标题 - 而不是您想要的。

单击确定,然后重建项目。

对我来说,这样做会导致 VC++ 控制台中出现以下错误(为简洁起见稍作编辑):

error C1189: #error :  'Use of iostream is prohibited'
IntelliSense: #error directive: 'Use of iostream is prohibited'
IntelliSense: namespace "std" has no member "cout"

请注意,IntelliSense 还会发现(现在)非法使用cout- 它在编辑器中以错误标记突出显示。

于 2013-08-12T01:46:53.920 回答
7

这是一个讨厌的黑客,但它应该工作。

C 标准(以及因此的 C++ 标准)允许在#include指令中使用预处理器标记。这也称为“计算包含”。

因此,如果有人尝试使用 iostream,在您的 makefile(或 IDE 项目设置中的编译器选项)中添加类似-DiostreamCFLAGS内容应该会可靠地破坏构建。

当然,如果使用空宏,错误消息不会提供太多信息,但您可以改用类似 的-Diostream=DUDE_DONT_USE_IOSTREAM内容,这将显示如下错误:DUDE_DONT_USE_IOSTREAM: file not found

如果您以后改变主意,您也可以毫不费力地再次关闭它。只需删除构建选项。

于 2013-08-12T10:08:07.063 回答
5

您检查符号文件的想法是可行且非常现实的。virtual ~ios_base();是所有流都将继承的单一方法,并且由于它是虚拟的且非平凡的,因此不容易内联。因此,它在目标文件中的存在是 IOstream 使用的一个非常强烈的指示。

于 2013-08-12T08:21:11.163 回答
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或类似(取决于平台)并注意导入的符号(如果您不说使用 iostreams 静态链接到某些东西,则此方法有效)。
于 2013-08-12T08:16:22.980 回答
-12

一点都不。对于非常有限的子集,您可以提供自己的定义,从而导致链接器在重复项处出错。不过,这将是非常未定义的行为。一个很好的部分是不受此影响的模板。如果不执行诸如删除 iostream 标头之类的激烈操作,或者使用诸如 Clang 之类的编译器并修改源代码,那么您真的无能为力。

于 2013-08-12T02:13:21.723 回答