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 formcxxx
.With the exception of
complex.h
, eachxxx.h
header included in the C++ standard library places in the global namespace each name that the correspondingcxxx
header would have placed in thestd
namespace.These headers are allowed to also declare the same names in the
std
namespace, and the correspondingcxxx
headers are allowed to also declare the same names in the global namespace: including<cstdlib>
definitely providesstd::malloc
and may also provide::malloc
. Including<stdlib.h>
definitely provides::malloc
and may also providestd::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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With