Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I stop GCC including standard library names into the global namespace?

When I use Standard C headers in C++, I generally prefer the forms which place identifiers into the std namespace, such as <cstdlib>. However, when I use these, GCC also places the names into the global namespace, which means that it will accept programs such as this:

#include <cstddef>

std::size_t x;
size_t y;

int main() {}

Here, the declaration of x is correct, but the declaration of y should be rejected if I want my code to be portable. (Note that if I included <stddef.h> instead of <cstddef>, GCC will correctly reject the declaration of x).

Can I get GCC to reject the declaration y above?

I compiled with all the pedantry and warnings I could think of:

-std=c++17 -pedantic -Wall -Wextra -Wpedantic -Weffc++

None of those seem to prevent GCC from accepting the non-portable form.


I'm now unsure whether I understand the rules correctly; my knowledge comes from this section in CPP Reference:

C compatibility headers

For some of the C standard library headers of the form xxx.h, the C++ standard library both includes an identically-named header and another header of the form cxxx.

With the exception of complex.h, each xxx.h header included in the C++ standard library places in the global namespace each name that the corresponding cxxx header would have placed in the std namespace.

These headers are allowed to also declare the same names in the std namespace, and the corresponding cxxx headers are allowed to also declare the same names in the global namespace: including <cstdlib> definitely provides std::malloc and may also provide ::malloc. Including <stdlib.h> definitely provides ::malloc and may also provide std::malloc. This applies even to functions and function overloads that are not part of C standard library.

To me, that last paragraph indicates that GCC's behaviour is permitted but not required, and therefore it's wrong to depend on it.

like image 531
Toby Speight Avatar asked Jun 22 '17 08:06

Toby Speight


1 Answers

The rule is that #include <xxx.h> (where xxx.h is the name of a standard C header) is required to define all the names required by the C standard for that header in the global namespace, and is allowed to also define those names (with the same meaning) in namespace std. Similarly, #include <cxxx> (where cxxx is the name of one of the standard C++ headers for the standard C library) is required to define all the names from the corresponding C header (with the same meaning) in the namespace std, and is allowed to also define those names in the global namespace.

Back in C++ 98 those headers were not allowed to add names to the other namespace. Some compiler couldn't do that. For example, if the C++ library writers don't control the C headers, the usual implementation technique is for the C++ header to #include the C header and hoist the C names into std with using declarations. So the rule was changed to reflect reality.

The language definition does not require those headers to put the names in both places; if it did, then the cxxx headers wouldn't be needed.

In short, you can't count on #include <cxxx> putting C names into the global namespace, but you also can't count on it not putting them there.

like image 129
Pete Becker Avatar answered Sep 22 '22 09:09

Pete Becker