1

I'm using a specific toolchain (the one that comes with the BlackBerry Playbook NDK). I think it's based on GCC 4.4.2. When I try compiling certain libraries with this toolchain, I run into strange issues with what I think is c++ global namespace stuff. For example, I'll get errors like:

'::sprintf' has not been declared

I never get these errors when linking against the GNU c++ standard library. However, the Playbook NDK uses the Dinkumware C++ libs by default and I always have to go through each error and usually add in the C equivalent (stdio.h in this case). For reasons beyond my control, I can't link to the GNU c++ standard library, which doesn't exhibit any of these problems.

If I'm trying to compile a bigger project, I can get hundreds of these errors. Is there a workaround that doesn't involve editing the source? In the above example, the file would usually include "cstdio" as a header, but that declares sprintf under the 'std' namespace. So the only options I have are to include the C header or add the std namespace.

4

3 回答 3

3

实际上,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_)

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

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

于 2012-06-10T17:59:15.650 回答
2

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

根据 C++ 标准:

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

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

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

于 2012-06-10T17:52:35.077 回答
0

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

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

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

g++ -include c_includes.h ...
于 2012-06-10T17:57:46.827 回答