Tim Rentsch said:
Keith Thompson said:
Tim Rentsch said:
But (C99 7.14.1.1p3):
If and when the function [the signal handler] returns, if
the value of sig is SIGFPE, SIGILL, SIGSEGV, or any other
implementation-defined value corresponding to a computational
exception [presumably this includes overflow on a signed integer
conversion], the behavior is undefined; otherwise the program
will resume execution at the point it was interrupted.
So if the particular undefined behavior of the implementation-defined
signal handler involves causing the conversion to yield a trap
representation, then yes, a trap representation can result from a
conversion.
It's undefined behavior. That means the implementation is free
to define it as yielding a trap representation, and isn't even
obligated to document that decision.
It doesn't seem terribly likely, though.
To me it does seem likely, precisely because the logic necessary
to effect a conversion is then so simple, eg, an arithmetic shift
left followed by a logical shift right. That there is no hardware
signal generated is irrelevant -- a signal raised in the abstract
machine need not have any corresponding presence in the physical
machine.
The whole idea is irrelevant except on systems that actually have trap
representations for integer types; there aren't many of those around
today. In addition, the implementation would have to support C99 (C90
didn't permit the implementation-defined signal), and the implementers
would have to decide to use signal semantics to justify the chosen
behavior.
First, it isn't just trap representations, it's also negative
zeros; the same argument about signal handling applies equally
to both.
Ok, so it applies only to systems that either have trap
representations for signed integers, or that use a representation
other than two's-complement. Again, there aren't many such systems.
Second, there is no reason that the implementation-defined result
of a narrowing conversion (to a signed integer type) can't be a
value that is not representable[*] in the type in question, which
means an exceptional condition, which means undefined behavior,
which means any value at all could be produced, including a trap
representation. Again the same argument applies to negative zeros;
the presence of undefined behavior trumps any other statement of
behavior that the Standard prescribes.
I've assumed that a trap representation cannot represent a value. But
C99 6.2.6.1p5, defining trap representations, says:
Certain object representations need not represent a value of the
object type.
which could be interpreted to mean that a trap representation *can*
represent a value of the type.
I'm not sure what that would mean, though; you wouldn't be able to
access the value without invoking undefined behavior. I suppose the
implementation could define the behavior of accessing a certain trap
representation as yielding a specified value; other operations on it
might have non-standard behavior. For example, addition and
subtraction might work properly on the full range of a type, but
multiplication and division might work only on a smaller subrange.
Third, as far as I know (not having a copy of the C90 Standard
handy), C90 didn't talk about either trap representations or
negative zeros, so questions about whether they can be generated
are irrelevant. However, C90 does have similar wording about
out-of-range values being exceptions and causing undefined
behavior, and that's really the important question here --
these kinds of conversions may produce bogus values under C90
as well as under C99.
Both C90 and C99 say that the result of a conversion from an integer
type to a signed integer type yields an implementation-defined result
if the source value can't be represented; C99 additionally allows an
implementation-defined signal to be raised -- which *can* invoke
undefined behavior. So I'd still say that the only way a conversion
can yield a trap representation is if the conversion raises a signal,
and the implementation chooses to define the undefined behavior so
that it stores a trap representation in the target object, which an
ordinary signal handler would have no way of accessing.
Oh, and that raises another point. A trap representation makes sense
only as something stored in an object. A conversion doesn't
necessarily involve any objects, so there's not necessarily any place
for the trap representation to exist.
[*] Notice, for example, the last sentence of 6.2.5p3: "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." Clearly the final clause
is necessary only if a resulting value might /not/ be within the
range of values that can be represented in the target type.
There are plenty of clauses in the standard that aren't strictly
necessary.
Possibly that conclusion came about because of a mistaken
interpretation of the C90 and C99 standards in this area. So if
my comments above are convincing, it might be worth revisiting
that conclusion.
I'm not convinced.