c ++全局命名空间编译问题

时间:2012-06-10 17:44:41

标签: c++ global-namespace

我正在使用特定的工具链(BlackBerry Playbook NDK附带的工具链)。我认为这是基于GCC 4.4.2。当我尝试用这个工具链编译某些库时,我遇到了奇怪的问题,我认为是c ++全局命名空间的东西。例如,我会收到如下错误:

'::sprintf' has not been declared

在链接GNU c ++标准库时,我从未遇到过这些错误。但是,Playbook NDK默认使用Dinkumware C ++库,我总是要经历每个错误并且通常添加C等价物(在本例中为stdio.h)。由于我无法控制的原因,我无法链接到GNU c ++标准库,它没有出现任何这些问题。

如果我正在尝试编译更大的项目,我可以获得数百个这样的错误。有没有涉及编辑源的解决方法?在上面的例子中,文件通常包含“cstdio”作为标题,但是在'std'命名空间下声明了sprintf。所以我唯一的选择是包含C头或添加std命名空间。

3 个答案:

答案 0 :(得分:3)

实际上,C ++标准要求在<c....>命名空间中可以访问标准库中声明的所有符号(包括std::标题中的C库)。它并不禁止它们出现在全局命名空间中,并且C ++标准库的某些实现(例如libstdc ++)已经选择将它们放在那里以实现向后兼容性。

您有几种可能性:

  • 您可以继续直接包含C标头(例如<stdio.h>),但通常不鼓励这样做,因为它们可能不会识别C ++并且可能会产生冲突(1)
  • 你可以为每个电话加前缀,但这可能是不切实际的
  • 您可以在文件顶部或每个功能中挑选您使用的符号:using std::printf;
  • 你可以直截了当地提出using namespace std;指令。但是你会拉很多东西......

我的个人建议是在呼叫前加上或挑选最常用的功能,然后将它们导入全局或当前命名空间。

就迁移而言,一种直接的可能性是实际“包装”标准标题:

// cstdio.hpp

#include <cstdio>

#if defined(_DIRKUMWARE_) // note: you'll have to research the symbol to check
namespace yournamespace {
    using std::printf;
    using std::vptrinf;
} // namespace yournamespace
#endif // defined(_DIRKUMWARE_)

然后让脚本替换代码库中<stdio.h><cstdio>的所有匹配项<cstdio.hpp>(显然,除此文件外)。这样,您可以针对标准库的每个实现调整此文件,而不是在包含这些函数的每个文件中重复处理。

注意(1):C标准没有规定功能是由功能还是宏提供。通常,minmax可能是宏。 C ++标准规定了函数,这就是使用C ++头文件通常更安全的原因。

答案 1 :(得分:2)

基本上你被困在一个角落里。

根据C ++标准:

  

包括cstdiostd命名空间中导入符号名称,在全局命名空间中导入可能

  

包括stdio.h在全局命名空间中导入符号名称,在std命名空间中导入可能

因此,如果在包含cstdio的特定实现中不导入全局命名空间中的符号,那么您唯一的选择是使用std命名空间的完全限定名称。
这是因为C ++标准很好地定义了这种行为,而这种行为并不常见。

答案 2 :(得分:0)

如果源包含一些常见的头文件,您可以修改那些包含所需内容的文件。

GCC有一个名为-include的命令行选项,允许您在编译其余文件之前强制源文件包含文件。您可以修改Makefile或项目构建脚本的等效项,以便为您执行包含。

// c_includes.h
#include <stdio.h>
#include <stdlib.h>
//...

g++ -include c_includes.h ...