

C standard library headers in C++
source link: https://maskray.me/blog/2022-05-15-c-standard-library-headers-in-c++
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C standard library headers in C++
In recent ISO C++ standards, [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" in the wording allows implementations to provide mix-and-match, e.g. std::exit
can be used with #include <stdlib.h>
and ::exit
can be used 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
and we get declarations in both the global namespace and the namespace std.
. /usr/include/c++/12/cstdlib
.. /usr/include/stdlib.h
The preprocessed output looks like:
extern void exit (int __status) noexcept (true) __attribute__ ((__noreturn__));
extern "C++"
{
namespace std __attribute__ ((__visibility__ ("default")))
{
using ::exit;
}
}
The compiler knows that the declarations in std
are identical to the ones in the global namespace. This property can be leveraged to do some optimizations as the compiler recognizes some library functions in the global namespace (e.g. many mem*
and str*
functions).
For some C standard library headers, libstdc++ provides wrappers (libstdc++-v3/include/c_compatibility/
) which take precedence over the glibc headers. The configuration of libstdc++ uses --enable-cheaders=c_global
by default. if GLIBCXX_C_HEADERS_C_GLOBAL
in libstdc++-v3/include/Makefile.am
describes that the 6 wrappers (complex.h, fenv.h, tgmath.h, math.h, stdatomic.h, stdlib.h
) shadow the C library headers of the same name. For example, #include <stdlib.h>
includes the wrapper stdlib.h
which includes cstdlib
, therefore bringing exit
into the namespace std.
. /usr/include/c++/12/stdlib.h
.. /usr/include/c++/12/cstdlib
... /usr/include/stdlib.h
In all --enable-cheaders
modes, #include <cstdlib>
also includes the corresponding C header, therefore we get declarations in both the global namespace and the namespace std.
. /usr/include/c++/12/cstdlib
.. /usr/include/stdlib.h
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.
string.h vs cstring
In an ISO C standard, [String handling] lists:
void *memchr(const void *s, int c, size_t n);
char *strchr(const char *s, int c);
char *strpbrk(const char *s1, const char *s2);
char *strstr(const char *s1, const char *s2);
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.
[cstring.syn] lists:
namespace std {
const void* memchr(const void* s, int c, size_t n); // see [library.c]
void* memchr(void* s, int c, size_t n); // see [library.c]
const char* strchr(const char* s, int c); // see [library.c]
char* strchr(char* s, int c); // see [library.c]
const char* strpbrk(const char* s1, const char* s2); // see [library.c]
char* strpbrk(char* s1, const char* s2); // see [library.c]
const char* strstr(const char* s1, const char* s2); // see [library.c]
char* strstr(char* s1, const char* s2); // see [library.c]
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:
namespace std {
const wchar_t* wcschr(const wchar_t* s, wchar_t c); // see [library.c]
wchar_t* wcschr(wchar_t* s, wchar_t c); // see [library.c]
const wchar_t* wcspbrk(const wchar_t* s1, const wchar_t* s2); // see [library.c]
wchar_t* wcspbrk(wchar_t* s1, const wchar_t* s2); // see [library.c]
const wchar_t* wcsrchr(const wchar_t* s, wchar_t c); // see [library.c]
wchar_t* wcsrchr(wchar_t* s, wchar_t c); // see [library.c]
const wchar_t* wcsstr(const wchar_t* s1, const wchar_t* s2); // see [library.c]
wchar_t* wcsstr(wchar_t* s1, const wchar_t* s2); // see [library.c]
const wchar_t* wmemchr(const wchar_t* s, wchar_t c, size_t n); // see [library.c]
wchar_t* wmemchr(wchar_t* s, wchar_t c, size_t n); // see [library.c]
}
[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_PROTO
was added to provide overloads for C++. Nowadays string.h
looks like:
/* Tell the caller that we provide correct C++ prototypes. */
#if defined __cplusplus && (__GNUC_PREREQ (4, 4) \
|| __glibc_clang_prereq (3, 5))
# define __CORRECT_ISO_CPP_STRING_H_PROTO
#endif
#ifdef __CORRECT_ISO_CPP_STRING_H_PROTO
extern "C++"
{
extern void *memchr (void *__s, int __c, size_t __n)
__THROW __asm ("memchr") __attribute_pure__ __nonnull ((1));
extern const void *memchr (const void *__s, int __c, size_t __n)
__THROW __asm ("memchr") __attribute_pure__ __nonnull ((1));
# ifdef __OPTIMIZE__
__extern_always_inline void *
memchr (void *__s, int __c, size_t __n) __THROW
{
return __builtin_memchr (__s, __c, __n);
}
__extern_always_inline const void *
memchr (const void *__s, int __c, size_t __n) __THROW
{
return __builtin_memchr (__s, __c, __n);
}
# endif
}
#else
extern void *memchr (const void *__s, int __c, size_t __n)
__THROW __attribute_pure__ __nonnull ((1));
#endif
In C++ mode, there are two memchr
extern "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
:
extern "C++"
{
namespace std __attribute__ ((__visibility__ ("default")))
{
using ::memchr;
}
}
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.
char *c1;
const char *cc1;
v1 = std::memchr (cv2, '/', 3); // { dg-error "invalid conversion" }
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):
// glibc string.h
extern void *memchr (const void *__s, int __c, size_t __n)
__THROW __attribute_pure__ __nonnull ((1));
// hypothetical cstring
namespace std __attribute__ ((__visibility__ ("default")))
{
// using ::memchr;
const void* memchr(const void* s, int c, size_t n);
void* memchr(void* s, int c, size_t n);
}
#if defined(__CORRECT_ISO_CPP_STRING_H_PROTO) || defined(_LIBCPP_MSVCRT) || \
defined(__sun__) || defined(_STRING_H_CPLUSPLUS_98_CONFORMANCE_)
#define _LIBCPP_STRING_H_HAS_CONST_OVERLOADS
#endif
#if defined(__cplusplus) && !defined(_LIBCPP_STRING_H_HAS_CONST_OVERLOADS) && defined(_LIBCPP_PREFERRED_OVERLOAD)
extern "C++" {
inline _LIBCPP_INLINE_VISIBILITY
char* __libcpp_strchr(const char* __s, int __c) {return (char*)strchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
const char* strchr(const char* __s, int __c) {return __libcpp_strchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
char* strchr( char* __s, int __c) {return __libcpp_strchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY
char* __libcpp_strpbrk(const char* __s1, const char* __s2) {return (char*)strpbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
const char* strpbrk(const char* __s1, const char* __s2) {return __libcpp_strpbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
char* strpbrk( char* __s1, const char* __s2) {return __libcpp_strpbrk(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY
char* __libcpp_strrchr(const char* __s, int __c) {return (char*)strrchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
const char* strrchr(const char* __s, int __c) {return __libcpp_strrchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
char* strrchr( char* __s, int __c) {return __libcpp_strrchr(__s, __c);}
inline _LIBCPP_INLINE_VISIBILITY
void* __libcpp_memchr(const void* __s, int __c, size_t __n) {return (void*)memchr(__s, __c, __n);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
const void* memchr(const void* __s, int __c, size_t __n) {return __libcpp_memchr(__s, __c, __n);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
void* memchr( void* __s, int __c, size_t __n) {return __libcpp_memchr(__s, __c, __n);}
inline _LIBCPP_INLINE_VISIBILITY
char* __libcpp_strstr(const char* __s1, const char* __s2) {return (char*)strstr(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
const char* strstr(const char* __s1, const char* __s2) {return __libcpp_strstr(__s1, __s2);}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_PREFERRED_OVERLOAD
char* strstr( char* __s1, const char* __s2) {return __libcpp_strstr(__s1, __s2);}
}
#endif
stdatomic.h in C++
C11 defines stdatomic.h
which defines several macros and declares several types and functions for performing atomic operations on data shared between threads. The header is shipped with the compiler (GCC, Clang).
https://wg21.link/P0943 (C++23) defines the semantics including stdatomic.h
in C++. Implementations:
Recommend
-
225
Modular standard library for JavaScript. Includes polyfills for ECMAScript up to 2021:
-
205
Go kit Go kit is a programming toolkit for building microservices (or elegant monoliths) in Go. We solve common problems in distributed systems and application architecture so you can focus on delivering...
-
111
headers A PHP library for working with HTTP and mail headers Install composer require ivoba/headers Version 2 requires minimum PHP7.1. Usage $header...
-
152
-
83
FancyToast-Android Prerequisites Add this in your root build.gradle file (not your module build.gradle file): allprojects { repositories { ... mavenCentral() } }
-
113
ΛRROW: Functional companion to Kotlin's Standard Library For the past 9 months a growing group of contributors have been working on bringing a complete Typ...
-
73
Why you should take a look at Kotlin's standard library ...
-
82
Ever wanted to return two values from a function? With Pairs this is rather easy to accomplish, you just have to use it as a return type. What’s more useful is that we can use destructuring to split…
-
92
README.md
-
39
Type::Tiny is probably best known as a way of having Moose-like type constraints in Moo , but it can be used for so...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK