Prevent standard functions outside of std namespac

2020-03-01 05:18发布

问题:

I am using only header files specific to C++ (e.g. <cstdlib>), however I still get globally-declared functions, and not just functions in the std namespace. Is there a way, perhaps a compiler switch, to prevent that?

For example, the following code:

#include <cstdlib>
float random() { return 0.0f; }
int main() { return 0; }

Fails to compile under linux, with the following error:

> g++ -c main.cpp main.o
main.cpp: In function ‘float random()’:
main.cpp:2:14: error: new declaration ‘float random()’
/usr/include/stdlib.h:327:17: error: ambiguates old declaration ‘long int random()’

or

> clang++ main.cpp -o main.o
main.cpp:2:7: error: functions that differ only in their return type cannot be overloaded
float random() { return 0.0f; }
/usr/include/stdlib.h:327:17: note: previous declaration is here
extern long int random (void) __THROW;

which is caused that stdlib.h "pollutes" the global namespace with its own random function.

Note, that I am not facing these problems when compiling on Windows, using Visual Studio.

回答1:

  1. <cstdlib> will always populate std namespace, and sometimes define global symbols, while <stdlib.h> will always define global symbols, and sometimes populate std namespace. This varies from implementation to implementation.

  2. The standard writes:

    Every C header, each of which has a name of the form name.h, behaves as if each name placed in the standard library namespace by the corresponding cname header is placed within the global namespace scope. It is unspecified whether these names are first declared or defined within namespace scope (3.3.6) of the namespace std and are then injected into the global namespace scope by explicit using-declarations (7.3.3).

    Which means, that the compiler is allowed to put those symbols into global scope and std namespace at the same time.

  3. Therefore, we see no advantages to prefer one header file over the other. Because they are both very likely to pollute the global scope.

    However, it is still necessary to use std namespace when #include <cstdlib>, and do not use std when #include <stdlib.h>, to make sure your code can compile for all compiler implementations.

  4. Advice: Do not use names in standard libraries. First, they are not guaranteed to work. (Note: Few compiler implementations actually keep the global scope clean when you #include <csomething>, so never depend on this.) Second, it will confuse code readers and maintainers, because almost everyone will assume standard names are actually standard, no matter where they come from.



回答2:

You can declare your functions in their own namespaces to prevent declaration collision.

namespace MyFunc
{
float random() { return 0.0f; }
};


回答3:

In general you should try to avoid redeclaring in the first place. You can do this by either using namespaces or by splitting up your source into files which can include cstdlib and others which can use a static version of your (name clashing) function.

If this is not an options then go on reading. But be aware that the following might be very platform specific.

By just having a look at my cstdlib and stdlib.h here at my place I noticed that there is a switch by which cstdlib decides if it includes stdlib.h or just declares abort, atext and exit in the std namespace.

Obviously you pull in the stdlib.h branch. Looking further into this file I noticed the macro __BEGIN_NAMESPACE_STD and later on __END_NAMESPACE_STD. Maybe you could use this, but it is (as the name suggests) some implementation internal macro and should not be set directly by you. However, it should be there for some reason so you might have luck with searching for it.

After some more search it turned out that random is one of several functions (and declarations) which are not wrapped into __BEGIN_NAMESPACE_STD. Therefore, this is not a solution to the problem. (I found another macro _GLIBCPP_USE_NAMESPACES which seems to be used internally as well to #define __BEGIN_NAMESPACE_STD namespace std {).

So to sum it up: This is no viable path and you should use one of the described workarounds.



回答4:

The standard explicitly permits <c???> headers to bring names of C standard functions to the global namespace.



回答5:

usually I would prefer to keep your function names different from what is defined as a standard . For ex here one could use function name as myRandom instead of random so that I can inform the people , who would be maintaining my code later on , that the function being used is NOT the one defined as a standard.



标签: c++ g++ clang++