thanks in advance for your help, tim
This one bothers me. We have:
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1310.htm
And it appears to have been corrected for C11. But aren't there some
unusual bits in C99 without the assumption that 'signed char' has no
padding bits?
"Expressions" @ 6.5p6 has:
"The effective type of an object for an access to its stored value is
the declared type of the object, if any.75) If a value is stored into an
object having no declared type through an lvalue having a type that is
not a character type, then the type of the lvalue becomes the effective
type of the object for that access and for subsequent accesses that do
not modify the stored value. 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. For all other accesses to an object having no declared type, the
effective type of the object is simply the type of the lvalue used for
the access."
This seems to suggest that an object's value _can_ be copied via:
- 'memcpy'
- 'memmove'
- treatment as an array of character type
If that value is a union value, and the union type goes:
union {
unsigned char bytes[10];
};
and if 'signed char' is a "character type" whose range of values cannot
be mapped to provide coverage for the range of 'unsigned char' values,
how can the union value be copied via treatment as an array of this
particular character type?
As another example assuming no padding bits, suppose "sign and
magnitude" representation is used for 'signed char'. With the sign bit
set and the value bits zero, we seem[6.2.6.2p2] to be allowed one of:
- a "trap representation"
- a normal value called a "negative zero"
Well 6.2.6.1p5 suggests that character types are exempt from having
trapresentations, so it looks like 'signed char' with "sign and
magnitude" _must_ support "negative zeroes." Fortunately, that doesn't
seem to mandate that _all_ signed types must support "negative zeroes."
(Right?)
Here's "General" @ 6.2.6.1p5:
"Certain object representations need not represent a value of the
object type. If the stored value of an object has such a representation
and is read by an lvalue expression that does not have character type,
the behavior is undefined. If such a representation is produced by a
side effect that modifies all or any part of the object by an lvalue
expression that does not have character type, the behavior is
undefined.41) Such a representation is called a trap representation."
The way I interpret this is: The first sentence talks about "certain
object representations." They are the overall subject for the entire
paragraph by their placement in the first sentence and by the later
references. They are qualified as being "[those representations that
do] not represent a value of the object type."
The second sentence refers to "such a representation," so is referring
to the very same representations as the first sentence.
The third sentence refers to "such a representation," so is referring to
the very same representations as the second and first sentences.
The fourth sentence refers to "such a representation," so is referring
to the very same representations as the third, second and first sentences.
Is this an agreeable interpretation? If so, it would seem to suggest that:
- Padding bits can be present in the object representation of a valid
object value (multiple representations for a value)
- Padding bits can be present in an object representation of an invalid
value and are part of that trap representation
It seems as though reading a stored object's value via any character
type is explicitly exempt from undefined behaviour. But if there are
padding bits in 'signed char' and no trap representations, doesn't that
suggest loss of information when copying the union value up above?
I'd like to ask: Although it's been "fixed" in C11, doesn't it already
follow from what we had in C99? Or is C99 sufficiently vague that
someone could claim that:
- sizeof (unsigned char) == sizeof (signed char)
- Rank of unsigned char < unsigned short < unsigned int[6.3.1.1p1, third
item)
- Rank of signed char < signed short < signed int
- Width of signed char < width of unsigned char
- Width of unsigned char < width of unsigned short < width of unsigned int
- Width of signed char < width of signed short < width of signed int
- Width of signed int < width of unsigned char?!
This would seem to result in some unusual circumstances, such as:
- not being able to write the maximum value for an 'unsigned char' as an
integer constant without some extended integer type supporting it[6.4.4.1p5]
- 'unsigned char' values promoting to 'unsigned int' but not to
'int'[6.3.1.1p2]