<html>
<head>
<title>P3370R1: Add new library headers from C23</title>

<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

<style type="text/css">
  ins { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
  .ins { text-decoration:none; background-color:#D0FFD0 }
  del { text-decoration:line-through; background-color:#FFA0A0 }  
  .del { text-decoration:line-through; background-color:#FFC0C0 }  
  strong { font-weight: inherit; color: #2020ff }
  table, td, th { border: 1px solid black; border-collapse:collapse; padding: 5px }
</style>
</head>

<body>
ISO/IEC JTC1 SC22 WG21 P3370R1<br/>
Jens Maurer &lt;Jens.Maurer@gmx.net><br/>
Target audience: LEWG<br/>
2024-10-06<br/>

<h1>P3370R1: Add new library headers from C23</h1>

<h2>Introduction</h2>

<p>
C23 added the <code>&lt;stdbit.h&gt;</code>
and <code>&lt;stdchkint.h&gt;</code> headers.  This paper proposes to
add these headers to C++ to increase the subset of code that compiles
with C and C++.
</p>

<p>
These interfaces are necessarily C-like; this proposal does not intend
to preclude adding a future C++ library facility that is in harmony
with prevalent C++ style.  In particular,
adding <code>&lt;cstd...&gt;</code> headers is not proposed.
</p>

<p>Type-generic macros and type-generic functions do not exist in C++,
but function templates can provide the same call interface.  Thus, the
use of the former in C is replaced by the latter in C++.</p>

<h2>Revision history</h2>

<UL>
<LI>R1: Address feedback from LEWG telecon review</LI>
</UL>

<h2>Wording</h2>

<p>Change in 16.4.2.4 [std.modules] as follows:</p>

<BLOCKQUOTE>

The named module <TT>std.compat</TT> exports the same declarations as
the named module <TT>std</TT>, and additionally exports
<UL>
<LI>declarations
in the global namespace corresponding to the declarations in namespace
<TT>std</TT> that are provided by the C++ headers for C library
facilities (Table 25), except the explicitly excluded declarations
described in 17.14.7 [support.c.headers.other] <ins>and</ins></LI>
<LI><ins>declarations provided by the
headers <TT>&lt;stdbit.h&gt;</TT> ([stdbit.h.syn])
and <TT>&lt;stdckdint.h&gt;</TT> ([stdckdint.h.syn])</ins>.
</LI>
</UL>

</BLOCKQUOTE>

<p>Add <code>&lt;stdbit.h&gt;</code>
and <code>&lt;stdckdint.h&gt;</code> to table [tab:c.headers] in
17.14.1 [support.c.headers.general].</p>

<p>Change in 17.14.7 [support.c.headers.other] as follows:</p>

<BLOCKQUOTE>

Every C header other than &lt;complex.h&gt; (17.14.2),
&lt;iso646.h&gt; (17.14.3), &lt;stdalign.h&gt; (17.14.4),
&lt;stdatomic.h&gt; (33.5.12), <ins>&lt;stdbit.h&gt; ([stdbit.h.syn]),</ins>
&lt;stdbool.h&gt; (17.14.5), <ins>&lt;stdckdint.h&gt;
([stdckint.h.syn]),</ins> and &lt;tgmath.h&gt; (17.14.6), each of
which has a name of the form &lt;name.h&gt;, behaves as if each name
placed in the standard library namespace by the corresponding
&lt;cname &gt; header is placed within the global namespace scope,
except for the functions described in 28.7.6, the std::lerp function
overloads (28.7.4), the declaration of std::byte (17.2.1), and the
functions and function templates described in 17.2.5. It is
unspecified whether these names are first declared or defined within
namespace scope (6.4.6) of the namespace std and are then injected
into the global namespace scope by explicit <I>using-declaration</I>s
(9.9).

</BLOCKQUOTE>

<p>Add a new subclause to clause 22 [utilities] as follows:</p>

<blockquote class="ins">

<h3>22.17 Header <code>&lt;stdbit.h&gt;</code> synopsis [stdbit.h.syn]</h3>

<pre>
#define __STDC_VERSION_STDBIT_H__ 202311L

#define __STDC_ENDIAN_BIG__     /* see below */
#define __STDC_ENDIAN_LITTLE__  /* see below */
#define __STDC_ENDIAN_NATIVE__  /* see below */

unsigned int stdc_leading_zeros_uc(unsigned char value);
unsigned int stdc_leading_zeros_us(unsigned short value);
unsigned int stdc_leading_zeros_ui(unsigned int value);
unsigned int stdc_leading_zeros_ul(unsigned long int value);
unsigned int stdc_leading_zeros_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_leading_zeros(T value);

unsigned int stdc_leading_ones_uc(unsigned char value);
unsigned int stdc_leading_ones_us(unsigned short value);
unsigned int stdc_leading_ones_ui(unsigned int value);
unsigned int stdc_leading_ones_ul(unsigned long int value);
unsigned int stdc_leading_ones_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_leading_ones(T value);

unsigned int stdc_trailing_zeros_uc(unsigned char value);
unsigned int stdc_trailing_zeros_us(unsigned short value);
unsigned int stdc_trailing_zeros_ui(unsigned int value);
unsigned int stdc_trailing_zeros_ul(unsigned long int value);
unsigned int stdc_trailing_zeros_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_trailing_zeros(T value);

unsigned int stdc_trailing_ones_uc(unsigned char value);
unsigned int stdc_trailing_ones_us(unsigned short value);
unsigned int stdc_trailing_ones_ui(unsigned int value);
unsigned int stdc_trailing_ones_ul(unsigned long int value);
unsigned int stdc_trailing_ones_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_trailing_ones(T value);

unsigned int stdc_first_leading_zero_uc(unsigned char value);
unsigned int stdc_first_leading_zero_us(unsigned short value);
unsigned int stdc_first_leading_zero_ui(unsigned int value);
unsigned int stdc_first_leading_zero_ul(unsigned long int value);
unsigned int stdc_first_leading_zero_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_first_leading_zero(T value);

unsigned int stdc_first_leading_one_uc(unsigned char value);
unsigned int stdc_first_leading_one_us(unsigned short value);
unsigned int stdc_first_leading_one_ui(unsigned int value);
unsigned int stdc_first_leading_one_ul(unsigned long int value);
unsigned int stdc_first_leading_one_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_first_leading_one(T value);

unsigned int stdc_first_trailing_zero_uc(unsigned char value);
unsigned int stdc_first_trailing_zero_us(unsigned short value);
unsigned int stdc_first_trailing_zero_ui(unsigned int value);
unsigned int stdc_first_trailing_zero_ul(unsigned long int value);
unsigned int stdc_first_trailing_zero_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_first_trailing_zero(T value);

unsigned int stdc_first_trailing_one_uc(unsigned char value);
unsigned int stdc_first_trailing_one_us(unsigned short value);
unsigned int stdc_first_trailing_one_ui(unsigned int value);
unsigned int stdc_first_trailing_one_ul(unsigned long int value);
unsigned int stdc_first_trailing_one_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_first_trailing_one(T value);

unsigned int stdc_count_zeros_uc(unsigned char value);
unsigned int stdc_count_zeros_us(unsigned short value);
unsigned int stdc_count_zeros_ui(unsigned int value);
unsigned int stdc_count_zeros_ul(unsigned long int value);
unsigned int stdc_count_zeros_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_count_zeros(T value);

unsigned int stdc_count_ones_uc(unsigned char value);
unsigned int stdc_count_ones_us(unsigned short value);
unsigned int stdc_count_ones_ui(unsigned int value);
unsigned int stdc_count_ones_ul(unsigned long int value);
unsigned int stdc_count_ones_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_count_ones(T value);

bool stdc_has_single_bit_uc(unsigned char value);
bool stdc_has_single_bit_us(unsigned short value);
bool stdc_has_single_bit_ui(unsigned int value);
bool stdc_has_single_bit_ul(unsigned long int value);
bool stdc_has_single_bit_ull(unsigned long long int value);
template&lt;class T> bool stdc_has_single_bit(T value);

unsigned int stdc_bit_width_uc(unsigned char value);
unsigned int stdc_bit_width_us(unsigned short value);
unsigned int stdc_bit_width_ui(unsigned int value);
unsigned int stdc_bit_width_ul(unsigned long int value);
unsigned int stdc_bit_width_ull(unsigned long long int value);
template&lt;class T> /* see below */ stdc_bit_width(T value);

unsigned char stdc_bit_floor_uc(unsigned char value);
unsigned short stdc_bit_floor_us(unsigned short value);
unsigned int stdc_bit_floor_ui(unsigned int value);
unsigned long int stdc_bit_floor_ul(unsigned long int value);
unsigned long long int stdc_bit_floor_ull(unsigned long long int value);
template&lt;class T> T stdc_bit_floor(T value);

unsigned char stdc_bit_ceil_uc(unsigned char value);
unsigned short stdc_bit_ceil_us(unsigned short value);
unsigned int stdc_bit_ceil_ui(unsigned int value);
unsigned long int stdc_bit_ceil_ul(unsigned long int value);
unsigned long long int stdc_bit_ceil_ull(unsigned long long int value);
template&lt;class T> T stdc_bit_ceil(T value);
</pre>

<p>For a function template whose return type is not specified above,
the return type is an implementation-defined unsigned integer type
large enough to represent all possible result values.  Each function
template has the same semantics as the corresponding type-generic
function with the same name specified in ISO/IEC 9899:2024, 7.18.</p>

<p>Mandates: <code>T</code> is an unsigned integer type.</p>

<p>Otherwise, the contents and meaning of the
header <code>&lt;stdbit.h&gt;</code> are the same as the C standard
library header <code>&lt;stdbit.h&gt;</code>.</p>

<p>See also: ISO/IEC 9899:2024, 7.18</p>

</blockquote>

<p>Add a new subclause to clause 28 [numerics] as follows:</p>

<blockquote class="ins">

<h3>28.10 C compatibility [numerics.c]</h3>

<h4>28.10.1 Header <code>&lt;stdckdint.h&gt;</code> synopsis [stdckdint.h.syn]</h4>

<pre>
#define __STDC_VERSION_STDCKDINT_H__ 202311L

template&lt;class type1, class type2, class type3&gt;
bool ckd_add(type1 *result, type2 a, type3 b);
template&lt;class type1, class type2, class type3&gt;
bool ckd_sub(type1 *result, type2 a, type3 b);
template&lt;class type1, class type2, class type3&gt;
bool ckd_mul(type1 *result, type2 a, type3 b);
</pre>

<p>See also: ISO/IEC 9899:2024, 7.20</p>

<h4>28.10.2 Checked integer operations [numerics.c.ckdint]</h4>

<pre>
template&lt;class type1, class type2, class type3&gt;
bool ckd_add(type1 *result, type2 a, type3 b);
template&lt;class type1, class type2, class type3&gt;
bool ckd_sub(type1 *result, type2 a, type3 b);
template&lt;class type1, class type2, class type3&gt;
bool ckd_mul(type1 *result, type2 a, type3 b);
</pre>

<p>Mandates: Each of the types <code>type1</code>, <code>type2</code>, and
<code>type3</code> is a cv-unqualified signed or unsigned integer
type.</p>

<p>Remarks: Each function template has the same semantics as the
corresponding type-generic macro with the same name specified in
ISO/IEC 9899:2024, 7.20.</p>

</blockquote>

</body>
