C standard library headers in C++
2022-5-15 15:0:0
Author: maskray.me(查看原文)
阅读量:30
收藏
In an ISO C++ standard, [depr.c.headers] describes how a C header name.h is transformed to the corresponding C++ cname header. There is a helpful example:
[ Example: The header assuredly provides its declarations and definitions within the namespace std. It may also provide these names within the global namespace. The header <stdlib.h> assuredly provides the same declarations and definitions within the global namespace, much as in the C Standard. It may also provide these names within the namespace std. — end example ]
"may also" allows implementations to have mix-and-match (e.g. std::exit with #include <stdlib.h and ::exit with #include <cstdlib>).
libstdc++ chooses to enable global namespace declarations with C++ cname header. For example, #include <cstdlib> also includes the corresponding C header stdlib.h. Therefore we get declarations in both the global namespace and the namespace std.
For some C standard library headers, libstdc++ provides wrappers (libstdc++-v3/include/c_compatibility/) which take precedence over the glibc headers. See if GLIBCXX_C_HEADERS_C_GLOBAL in libstdc++-v3/include/Makefile.am for the 6 wrappers (complex.h, fenv.h, tgmath.h, math.h, stdatomic.h, stdlib.h). This means #include <stdlib.h> will provide std::exit.
The mix-and-match mechanism looks gross, but it has been needed for compatibility in the ancient days. Nowadays, I can imagine widespread breakage if we drop the mix-and-match.
Note that the return types do not have the const qualifier, e.g. memchr would better return a const void *. Unfortunately that is not the case likely due to backward compatibility: the const qualifier does not exist in The C Programming Language (1st edition, 1978). The C Programming Language (2nd edition, 1988) introduces the const qualifier, adds the const qualifier to some arguments, but does not change the return type probably because that would break code.
In the current ISO C++ standard, [library.c] says
The descriptions of many library functions rely on the C standard library for the semantics of those functions. In some cases, the signatures specified in this document may be different from the signatures in the C standard library, and additional overloads may be declared in this document, but the behavior and the preconditions (including any preconditions implied by the use of an ISO C restrict qualifier) are the same unless otherwise stated.
There is an apparent attempt to correct the mistakes as evidenced by the note:
[Note 1: The functions strchr, strpbrk, strrchr, strstr, and memchr, have different signatures in this document, but they have the same behavior as in the C standard library. — end note]
In glibc string.h, some extensions have similar overloads: rawmemchr, strchrnul, strcasestr, basename.
wchar.h vs cwchar
Similar differences apply to wchar.h vs cwchar. C++ [cwchar.syn] lists the following functions with different signatures:
[Note 1: The functions wcschr, wcspbrk, wcsrchr, wcsstr, and wmemchr have different signatures in this document, but they have the same behavior as in the C standard library. — end note]
glibc __CORRECT_ISO_CPP_STRING_H_PROTO
In 2009, __CORRECT_ISO_CPP_STRING_H_PROTOwas added to provide overloads for C++. Nowadays string.h looks like:
In C++ mode, there are two memchrextern "C++" overloads. To prevent C++ name mangling, asm labels (__asm ("memchr")) are used. (__glibc_clang_prereq (3, 5) was added as the resolution to https://sourceware.org/bugzilla/show_bug.cgi?id=25232.)
The code fragment is used together with the following fragment in libstdc++ cstring:
There is a similar macro __CORRECT_ISO_CPP_WCHAR_H_PROTO for wchar.h.
With the glibc and libstdc++ cooperation, the following code (adapted from libstdc++-v3/testsuite/21_strings/c_strings/char/3_neg.cc) will get a compile error.
1 2 3 4
char *c1; constchar *cc1;
v1 = std::memchr (cv2, '/', 3);
If we modify glibc string.h by undefining __CORRECT_ISO_CPP_STRING_H_PROTO, the compile error will go away.
IMO it would look better if we did this (dropping the feature that declarations match in std and the global namespace):