【问题标题】:c++ global namespace compile problemsc++全局命名空间编译问题
【发布时间】:2012-06-10 17:44:41
【问题描述】:

我正在使用特定的工具链(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 命名空间。

【问题讨论】:

  • 你应该添加<cstdio>而不是stdio.h
  • 抱歉,我编辑了我的帖子以反映发生的情况。源文件通常包含 cstdio。但它会抛出一个错误,除非我在 std 命名空间下添加函数调用。
  • 他的问题是<cstdio> 声明了std 命名空间下的所有内容。他正在使用<stdio.h> 来解决这个问题,并想知道是否有其他方法。我认为没有,除了用stdusing namespace std; 作为前缀。
  • 使用 GNU STL 并不能解决这个问题。
  • 对我有用。需要明确的是,我正在尝试使用这个特定的工具链移植项目。如果我尝试用我的台式机编译相同的项目,我不会有任何问题,它会正常工作。但是同一个项目不会用工具链编译。此外,如果我强制工具链使用 g++ 驱动程序而不是其默认的 qcc 驱动程序,则一切编译正常。两者之间的区别是 qcc 驱动程序链接针对 Dinkumware 库和 g++ 链接针对 GNU stl。我不知道这两种方法之间有什么其他区别。

标签: c++ global-namespace


【解决方案1】:

实际上,C++ 标准要求标准库中声明的所有符号(包括 <c....> 标头中的 C 库)都可以在 std:: 命名空间中访问。它并不禁止它们出现在全局命名空间中,并且出于向后兼容性的原因,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_)

然后让脚本将代码库中所有出现的&lt;stdio.h&gt;&lt;cstdio&gt; 替换为&lt;cstdio.hpp&gt;(显然在这个文件中除外)。这样,您可以针对标准库的每个实现调整此文件,而不是在每个包含这些函数的文件中重复工作。

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

【讨论】:

    【解决方案2】:

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

    根据 C++ 标准:

    包括cstdio 会在std 命名空间中导入符号名称,可能在全局命名空间中。

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

    因此,如果在包括 cstdio 在内的特定实现中不导入全局命名空间中的符号,那么您唯一的选择是使用 std 命名空间的完全限定名称。
    这是因为 C++ 标准对行为进行了很好的定义,只是不太为人所知。

    【讨论】:

      【解决方案3】:

      如果源包含一些常见的头文件,您可以使用所需的包含来修改它们。

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

      // c_includes.h
      #include <stdio.h>
      #include <stdlib.h>
      //...
      
      g++ -include c_includes.h ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-31
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 2012-05-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多