Closed Eisenwave closed 1 year ago
Related: https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#350. This rejected issue suggested to defined char
, signed char
, and unsigned char
as byte-character types, and followed a similar strategy in relaxing requirements. However, this was rejected with:
The CWG was not convinced that there was a need to change the existing specification at this time. Some were concerned that there might be implementation difficulties with giving
signed char
the requisite semantics; implementations for which that is true can currently makechar
equivalent tounsigned char
and avoid those problems, but the suggested change would undermine that strategy.
This new issue does not attempt to give signed char
the same semantics as unsigned char
. Instead, char
can be made unsigned by the implementation, and all the proposed changes become implementable.
The inconsistencies are intentional. Historic CWG discussions were clear that new facilities should not consider char
special, and, in hindsight, it was a mistake to e.g. extend the special aliasing allowances to char
.
That's why std::byte
was introduced, and there was the hope we can eventually remove char
from any of the special exception lists it is currently on. Maybe in a decade or two.
Any change of direction in this area needs a paper to EWG; it is out of scope for a core issue.
Full name of submitter): Jan Schultke
Reference (section label): [basic.fundamental]
Issue Description
The Status Quo in the C++ Standard
Numerous sections in the C++ standard have an implicit notion of a byte-like type. This always includes
unsigned char
andstd::byte
, sometimes includes unsigned ordinary character types (presumable includes achar
which's underlying type isunsigned char
), and sometimes includeschar
.signed char
is never considered to be a byte-like type:unsigned char[]
andstd::byte[]
to provide storageunsigned char[]
andstd::byte[]
to implicitly create objectschar*
, cvunsigned char*
, and cvstd::byte*
in situations where other casts are not possiblestd::byte
char[]
,unsigned char[]
, andstd::byte[]
char
,unsigned char
, andstd::byte
char[]
,unsigned char[]
, andstd::byte[]
specially in a new-expressionstd::byte
Confusing Effects of the Status Quo
The problem with the status quo is that every section has its own concept of a byte-like type, and this concept is never formalized by any. This leads to surprising and illogical inconsistencies, such as:
char*
can alias any object, but achar[]
doesn't provide storage for an object.char[]
allocated with a new-expression is maximally aligned just likeunsigned char[]
(presumably so that it can provide storage), but achar[]
cannot provide storage unlikeunsigned char[]
.char[]
is possible, and implicitly creates objects if done throughstd::memcpy
, but beginning the lifetime of achar[]
does not implicitly create objects in itself (onlyunsigned char[]
has that property).unsigned char[]
may be safe due to the relaxations in [basic.indet], however, copying intochar[]
isn't safe. This is particularly dangerous because trivially copyable types allow transfer of values throughchar[]
, but this is seemingly not allowed if any bytes are indeterminate.Why
char
Should Be Universally Byte-LikeIt is obvious that some definition of a byte-like type would be useful, however, it is not obvious whether
char
should be included in such a definition, and when. The advantages of universally consideringchar
to be byte-like are:char
always enjoys exactly the same special treatment asstd::byte
char
, but only if its underlying type isunsigned char
) are no longer a portability issue, sincechar
is always allowed to take indeterminate values, not just in some implementationschar
should be treated as byte-like in new language features or not; a precedent like this is usefulMinor Negative Consequences of a Byte-Like
char
The main downside to making
char
byte-like is thatchar[]
can provide storage and implicitly create objects. Whenchar[]
is used as a string, and not as a byte-like type, this behavior can be surprisingly permissive. However, this is not a safety issue, and the opportunities for compilers to utilize this restriction for the purpose of optimization are rare, especially considering thatchar*
can alias any other pointer already.Suggested Resolution
Unify the definition of a byte-like type. To [basic.fundamental] p7 (or to a separate paragraph) add:
In [intro.object] p3:
In [intro.object] p13:
In [basic.indet] (multiple paragraphs), as well as in [bit.cast] p2:
Editorial Changes
The following sections already consider
char
to be byte-like, and are only affected editorially.In [basic.life] p6.4:
In [basic.types.general] p2:
In [basic.lval] p11.3:
In [expr.new] p16: