c++ global namespace compile problems

3.8k views Asked by At

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.

3

There are 3 answers

0
Matthieu M. On BEST ANSWER

Actually, the C++ standard mandates that all symbols declared in the Standard Library (which include the C Library in the <c....> headers) be accessible in the std:: namespace. It does not forbid them to also appear in the global namespace, and some implementations of the C++ Standard Library such as libstdc++ have chosen to let them there for backward compatibility reasons.

You have several possibilities:

  • you can continue to include the C headers directly (like <stdio.h>) however it is generally discouraged as they may not be C++ aware and might create clashes (1)
  • you can prefix each call, though it may be impractical
  • you can cherry pick the symbols you use: using std::printf; either at the top of the file or within each function
  • you can bluntly put a using namespace std; directive. However you'll be pulling a lot of stuff...

My personal recommendation is to either prefix the call or cherry-pick the most used functions and import them in the global or current namespace.

In terms of a migration, one blunt possibility is to actually "wrap" the standard headers:

// 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_)

And then have a script replace all occurrences of <stdio.h> and <cstdio> in the code base by <cstdio.hpp> (apart in this file, obviously). This way you can tune this file for each implementation of the standard library, instead of repeating the work arounds in each and every file that includes those functions.

Note (1): the C Standard does not mandate whether the functionality be provided by a function or a macro. Typically, min and max might be macros. The C++ Standard mandates functions, which is why using the C++ headers is normally safer.

0
Alok Save On

Basically you are stuck in a corner.

As per the C++ Standard:

Including cstdio imports the symbol names in std namespace and possibly in Global namespace.

and

Including stdio.h imports the symbol names in Global namespace and possibly in std namespace.

So if in a particular implementation including cstdio doesn't import the symbols in global namespace then the only option you have is to use the fully qualified name for the std namespace.
This is because the behavior is well defined by the C++ Standard just not so commonly known.

0
jxh On

If there are a few common header files that the sources include from, you can just modify those with the inclusions you need.

GCC has a command line option called -include that allows you to force a source file to include a file before the rest of it gets compiled. You could modify your Makefile, or project building script's equivalent, to do the inclusions for you.

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

g++ -include c_includes.h ...