Title
signed char underlying representation for objects
Status
open
Section
6.9 [basic.types]
Submitter
Noah Stein

Created on 2002-04-16.00:00:00, last changed 2014-11-24.00:00:00.

Messages

Date: 2014-11-24.00:00:00

Additional note, November, 2014:

There is now the term “narrow character type” that should be used instead of “byte-character type”.

Date: 2010-03-15.00:00:00

Notes from the March, 2010 meeting:

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 make char equivalent to unsigned char and avoid those problems, but the suggested change would undermine that strategy.

Date: 2010-02-15.00:00:00

Proposed resolution (February, 2010):

  1. Change 6.8 [basic.life] paragraph 5 bullet 4 as follows:

  2. ...The program has undefined behavior if:

    • ...

    • the pointer is used as the operand of a static_cast (8.2.9 [expr.static.cast]) (except when the conversion is to cv void*, or to cv void* and subsequently to char*, or unsigned char* a pointer to a cv-qualified or cv-unqualified byte-character type (6.9.1 [basic.fundamental])), or

    • ...

  3. Change 6.8 [basic.life] paragraph 6 bullet 4 as follows:

  4. ...The program has undefined behavior if:

    • ...

    • the lvalue is used as the operand of a static_cast (8.2.9 [expr.static.cast]) except when the conversion is ultimately to cv char& or cv unsigned char& a reference to a cv-qualified or cv-unqualified byte-character type (6.9.1 [basic.fundamental]) or an array thereof, or

    • ...

  5. Change 6.9 [basic.types] paragraph 2 as follows:

  6. For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object holds a valid value of type T, the underlying bytes (4.4 [intro.memory]) making up the object can be copied into an array of char or unsigned char a byte-character type (6.9.1 [basic.fundamental]).39 If the content of the that array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value. [Example:...
  7. Change 6.9.1 [basic.fundamental] paragraph 1 as follows:

  8. ...Characters can be explicitly declared unsigned or signed. Plain char, signed char, and unsigned char are three distinct types, called the byte-character types. A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (6.11 [basic.align]); that is, they have the same object representation. For byte-character types, all bits of the object representation participate in the value representation. For unsigned character types unsigned char, all possible bit patterns of the value representation represent numbers...
  9. Change 6.10 [basic.lval] paragraph 15 final bullet as follows:

  10. If a program attempts to access the stored value of an object through an lvalue of other than one of the following types the behavior is undefined 52

    • ...

    • a char or unsigned char byte-character type (6.9.1 [basic.fundamental]).

  11. Change 6.11 [basic.align] paragraph 6 as follows:

  12. The alignment requirement of a complete type can be queried using an alignof expression (8.3.6 [expr.alignof]). Furthermore, the byte-character types (6.9.1 [basic.fundamental]) char, signed char, and unsigned char shall have the weakest alignment requirement. [Note: this enables the byte-character types to be used as the underlying type for an aligned memory area (10.6.2 [dcl.align]). —end note]
  13. Change 8.3.4 [expr.new] paragraph 10 as follows:

  14. ...For arrays of char and unsigned char a byte-character type (6.9.1 [basic.fundamental]), the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the strictest fundamental alignment requirement (6.11 [basic.align]) of any object type whose size is no greater than the size of the array being created. [Note: Because allocation functions are assumed to return pointers to storage that is appropriately aligned for objects of any type with fundamental alignment, this constraint on array allocation overhead permits the common idiom of allocating byte-character arrays into which objects of other types will later be placed. —end note]
Date: 2004-10-15.00:00:00

Notes from October 2004 meeting:

The C99 Standard appears to be inconsistent in its requirements. For example, 6.2.6.1 paragraph 4 says:

The value may be copied into an object of type unsigned char [n] (e.g., by memcpy); the resulting set of bytes is called the object representation of the value.

On the other hand, 6.2 paragraph 6 says,

If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.

Mike Miller will investigate further.

Date: 2003-10-15.00:00:00

Notes from October 2003 meeting:

It appears that in C99 signed char may have padding bits but no trap representation, whereas in C++ signed char has no padding bits but may have -0. A memcpy in C++ would have to copy the array preserving the actual representation and not just the value.

March 2004: The liaisons to the C committee have been asked to tell us whether this change would introduce any unnecessary incompatibilities with C.

Date: 2003-04-15.00:00:00

Proposed resolution (April 2003):

Change 6.8 [basic.life] paragraph 5 bullet 3 from

  • the pointer is used as the operand of a static_cast (8.2.9 [expr.static.cast]) (except when the conversion is to void*, or to void* and subsequently to char*, or unsigned char*).

to

  • the pointer is used as the operand of a static_cast (8.2.9 [expr.static.cast]) (except when the conversion is to void*, or to void* and subsequently to a pointer to byte-character type).

Change 6.8 [basic.life] paragraph 6 bullet 3 from

  • the lvalue is used as the operand of a static_cast (8.2.9 [expr.static.cast]) (except when the conversion is ultimately to char& or unsigned char&), or

to

  • the lvalue is used as the operand of a static_cast (8.2.9 [expr.static.cast]) (except when the conversion is ultimately to a reference to byte-character type), or

Change the beginning of 6.9 [basic.types] paragraph 2 from

For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid value of type T, the underlying bytes (4.4 [intro.memory]) making up the object can be copied into an array of char or unsigned char.

to

For any object (other than a base-class subobject) of POD type T, whether or not the object holds a valid value of type T, the underlying bytes (4.4 [intro.memory]) making up the object can be copied into an array of byte-character type.

Add the indicated text to 6.9.1 [basic.fundamental] paragraph 1:

Objects declared as characters (char) shall be large enough to store any member of the implementation's basic character set. If a character from this set is stored in a character object, the integral value of that character object is equal to the value of the single character literal form of that character. It is implementation-defined whether a char object can hold negative values. Characters can be explicitly declared unsigned or signed. Plain char, signed char, and unsigned char are three distinct types, called the byte-character types. A char, a signed char, and an unsigned char occupy the same amount of storage and have the same alignment requirements (6.9 [basic.types]); that is, they have the same object representation. For byte-character types, all bits of the object representation participate in the value representation. For unsigned byte-character types, all possible bit patterns of the value representation represent numbers. These requirements do not hold for other types. In any particular implementation, a plain char object can take on either the same values as a signed char or an unsigned char; which one is implementation-defined.

Change 6.10 [basic.lval] paragraph 15 last bullet from

  • a char or unsigned char type.

to

  • a byte-character type.
Date: 2002-10-15.00:00:00

Notes from October 2002 meeting:

We should do whatever C99 does. 6.5p6 of the C99 standard says "array of character type", and "character type" includes signed char (6.2.5p15), and 6.5p7 says "character type". But see also 6.2.6.1p4, which mentions (only) an array of unsigned char.

Date: 2002-04-16.00:00:00

Sent in by David Abrahams:

Yes, and to add to this tangent, 6.9.1 [basic.fundamental] paragraph 1 states "Plain char, signed char, and unsigned char are three distinct types." Strangely, 6.9 [basic.types] paragraph 2 talks about how "... the underlying bytes making up the object can be copied into an array of char or unsigned char. If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value." I guess there's no requirement that this copying work properly with signed chars!

History
Date User Action Args
2014-11-24 00:00:00adminsetmessages: + msg5238
2010-03-29 00:00:00adminsetmessages: + msg2585
2010-03-29 00:00:00adminsetstatus: review -> open
2010-02-16 00:00:00adminsetmessages: + msg2524
2010-02-16 00:00:00adminsetstatus: drafting -> review
2004-11-07 00:00:00adminsetmessages: + msg1075
2004-11-07 00:00:00adminsetstatus: review -> drafting
2003-11-15 00:00:00adminsetmessages: + msg918
2003-04-25 00:00:00adminsetmessages: + msg816
2003-04-25 00:00:00adminsetstatus: drafting -> review
2002-11-08 00:00:00adminsetmessages: + msg748
2002-11-08 00:00:00adminsetstatus: open -> drafting
2002-04-16 00:00:00admincreate