jameskuyper said:
Tim said:
jameskuyper said:
CBFalconer wrote:
blargg wrote:
... snip ...
BTW, in another message in this thread someone said that shifting
a signed value right is undefined. My copy of the C99 standard
says otherwise:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If
E1 has an unsigned type or if E1 has a signed type and a
nonnegative value, the value of the result is the integral part
of the quotient of E1 / 2^E2. If E1 has a signed type and a
negative value, the resulting value is implementation-defined.
Your quote (repeated above) specifies implementation-defined. This
also means that you don't know what your code will do on another
compiler or system.
You're confusing "implementation-defined value" with "undefined
behavior", which is precisely the distinction he's making. If the
behavior were undefined, as was incorrectly claimed, it would indeed
be the case that "you don't know what your code will do on another
machine", and the implemenation for that other machine has no
obligation to document what that behavior will be.
Since the behavior is in fact implementation-defined, you know that
such code will produce a valid value of the specified type, no matter
which conforming implementation you use. [...]
Except that 6.2.6.2 p 4 means there can be undefined behavior:
If the implementation does not support negative zeros, the
behavior of the &, |, ^, ~, <<, and >> operators with arguments
that would produce such a value is undefined.
3.17.1: "implementation-defined value
unspecified value where each implementation documents how the choice
is made"
3.17.1: "unspecified value
valid value of the relevant type where this International Standard
imposes no
requirements on which value is chosen in any instance."
Therefore, an implementation-defined value is required to be a valid
value. On a system where negative zeros are not valid, they can never
be that implementation's choice in any situation where the standard
says that a value is implementation-defined. This means that 6.2.6.2p4
can only apply when the result is NOT implementation-defined.
This interpretation has a problem: with this interpretation, I can't
find any way to apply 6.2.6.2p4 to any operation involving either
shift operator that would otherwise have defined behavior, so
inclusion of the shift operators in 6.2.6.2p4 seems to be redundant;
it does not, however, contradict anything said elsewhere. For the
other four operators, it's trivial to come up with cases where the
resulting value would otherwise be standard-defined as the one
represented by the bit pattern for negative zero, if it weren't for
the fact that this clause renders the behavior undefined.
I acknowlege the apparent conflict between the two sections
(namely, 6.2.6.2 p 4 and the description of >> in 6.5.7 p 5). In
light of the problem (as you point out) of there being no reason
for the inclusion of >> in 6.2.6.2 p 4, the only interpretation I
can find that makes any sense is that the phrase "the resulting
value is implementation-defined" (given in 6.5.7 p 5) admits the
possibility that an implementation can define the resulting value
in such a way that the undefined behavior provision of 6.2.6.2p4
can be invoked. In short, an implementation can choose to select
undefined behavior here if it wants to.
There is further evidence that the phrase "the resulting value is
implementation-defined" doesn't always mean a valid value is
produced. Consider these two sentences together:
(from 6.5.7 p 5):
If E1 has a signed type and a negative value, the resulting value
is implementation-defined.
(from 6.2.5 p 3):
If any other character is stored in a char object, the resulting
value is implementation-defined but shall be within the range of
values that can be represented in that type.
There is no reason for the clause after the "but" in 6.2.5p3
unless "the resulting value is implementation-defined" admits
the possibility that a non-valid value might otherwise be
produced.
There is also 6.5p4:
Some operators (the unary operator ~, and the binary operators <<, required to have operands that have integer type. These operators
yield values that depend on the internal representations of
integers, and have implementation-defined and undefined aspects
for signed types.
The only way that >> can have "undefined aspects" is if 6.5.7 p 5
allows some of the implementation-defined results to invoke
undefined behavior.
Taking all of these together, it seems clear that the Standard
allows >> to be defined (at least in some implementations) so that
some operand values invoke undefined behavior.