plain int and signed int

K

Keith Thompson

Tim Rentsch said:
Right, but an out-of-range value is being converted:

6.3.1.3 Signed and unsigned integers

3 Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.

The implementation-supplied signal handler for this signal is
free to use &, |, etc, to generate a result for the conversion.
Remember the semantics of default signal handlers are
implementation-defined.

A user-written signal handler can't have the visibility necessary to
generate a result for the conversion. I'm not convinced that an
implementation-defined signal handler can do so either, unless by
taking advantage of undefined behavior.

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 doesn't seem terribly likely, though.
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
Right, but an out-of-range value is being converted:

6.3.1.3 Signed and unsigned integers

3 Otherwise, the new type is signed and the value cannot be
represented in it; either the result is implementation-defined
or an implementation-defined signal is raised.

The implementation-supplied signal handler for this signal is
free to use &, |, etc, to generate a result for the conversion.
Remember the semantics of default signal handlers are
implementation-defined.

A user-written signal handler can't have the visibility necessary to
generate a result for the conversion. I'm not convinced that an
implementation-defined signal handler can do so either, unless by
taking advantage of undefined behavior.

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.
 
E

Eric Sosman

Clarification: all integer types _in any particular implmentation_.
Obviously different implementations can make different choices.


In fact I think that's right -- an implementation can have exact-width
integer types, or use a { 1's complement, s/m } representation, but
not both.


No, an implementation can have CHAR_BIT be any of those values but
use a representation other than 2's complement, in which case it
won't have exact-width integer types. N1256 is explicit that
having a 2's complement representation is a pre-requisite for
requiring the exact width types be defined.

7.18.1.1p3: "These types are optional. However, if an
implementation provides integer types with widths of 8, 16,
32, or 64 bits, it shall define the corresponding typedef
names." That's "shall," not "may."

The implementation necessarily provides at least three
integer types that are exactly CHAR_BIT bits wide, and at
least one of those is signed. Thus if CHAR_BIT is 8, say,
the implementation must define int8_t. That type must use
two's complement representation, regardless of what is used
by `signed char'. Similarly for CHAR_BIT of 16, 32, or 64.
 
T

Tim Rentsch

Eric Sosman said:
7.18.1.1p3: "These types are optional. However, if an
implementation provides integer types with widths of 8, 16,
32, or 64 bits, it shall define the corresponding typedef
names." That's "shall," not "may."

The implementation necessarily provides at least three
integer types that are exactly CHAR_BIT bits wide, and at
least one of those is signed. Thus if CHAR_BIT is 8, say,
the implementation must define int8_t. That type must use
two's complement representation, regardless of what is used
by `signed char'. Similarly for CHAR_BIT of 16, 32, or 64.

I think you're referring to a pre-corrected text. I believe this
change was made as part of TC1 or TC2. Both N1124 and N1256 say
for 7.18.1.1p3:

These types are optional. However, if an implementation
provides integer types with widths of 8, 16, 32, or 64 bits, no
padding bits, and (for the signed types) that have a two's
complement representation, it shall define the corresponding
typedef names.

with a change bar by the part of the line with "padding bits", etc.

Since exact width types are required to be two's complement (per
7.18.1.1p1) the change to 7.18.1.1p3 had to be made, otherwise no
implementation with CHAR_BIT == 8 (or 16, 32, 64) could use ones'
complement or signed magnitude representations. (For that matter,
the types of those widths couldn't have padding bits either.)
Surely there was no intention to exclude such implementations. Or
do you mean to suggest that implementations having types of those
widths may use ones' complement or signed magnitude only if they
_also_ implement a set of two's complement types just for the exact
width types? It seems nutty to require such a thing.

I believe the current C99 standard allows implementations to have
CHAR_BIT == 8, 16, 32, or 64, use one's complement or signed
magnitude representation, and not define any of the exact width
integer types described in 7.18.1.1.
 
E

Eric Sosman

I think you're referring to a pre-corrected text.

It's from ISO/IEC 9899:1999(E), the original C99. I admit
I haven't kept up with the post-2000 updates.

The real issue, though, isn't the circumstances under which
exact-width types are required, but your contention that all
integer types must use the same scheme (two's complement,
ones' complement, or signed magnitude). I brought up the exact-
width stuff as a gentle way of ridiculing the contention; can
you find any actual support for it?
 
K

Keith Thompson

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.

As I said, it doesn't seem terribly likely.
 
P

Phil Carmody

Joe Wright said:
No. (-0) is counter-intuitive to me. I learned two's complement in
1963 and have never encountered an actual machine which used anything
else. I also learned one's complement and signed-magnitude at the same
time but have never seen them used in practice.

So you've never encountered any floating point numbers, then?

Phil
 
P

Phil Carmody

Joe Wright said:
Is that supposed to be clever? You lose. In C (-0) is integral, not
floating point. Perhaps you mean (-0.0)? Subject: plain int and signed
int, not float.

You were talking about the methods of representation, not the
applications. The representation (having a sign bit which
represents nothing but the sign, and does not affect the
absolute value) is used in floating point units.

Phil
 
S

Squeamizh

You were talking about the methods of representation, not the
applications. The representation (having a sign bit which
represents nothing but the sign, and does not affect the
absolute value) is used in floating point units.

Read again. He said he's never seen one's complement or sign-magnitude
in the real world. That has nothing to do with floating point.
 
P

Peter Nilsson

I do recall someone mentioning (or theorising) about a machine
that only had a floating point unit that implemented integers
using a non-normalised representation. The exponent would simply
be padding bits. (...and UINT_MAX would equal INT_MAX.)
Read again. He said he's never seen one's complement or sign-
magnitude in the real world. That has nothing to do with
floating point.

Neither of you can recognise, let alone acknowledge, the
similarity between sign-mantissa and exponent-sign-mantissa?

If Joe's ever written -1 on a piece of paper, then he has
seen sign-magnitude in the real world, even if he's never
seen it implemented for integers on a cpu.

But from what I read, people are still designing the odd DSP
chip to use sign-magnitude integers.
 
S

Squeamizh

I do recall someone mentioning (or theorising) about a machine
that only had a floating point unit that implemented integers
using a non-normalised representation. The exponent would simply
be padding bits. (...and UINT_MAX would equal INT_MAX.)



Neither of you can recognise, let alone acknowledge, the
similarity between sign-mantissa and exponent-sign-mantissa?

If Joe's ever written -1 on a piece of paper, then he has
seen sign-magnitude in the real world, even if he's never
seen it implemented for integers on a cpu.

This might come as a shock to you (please brace yourself) - a CPU does
not contain a little man with a pencil and paper.
 
E

Eric Sosman

[...]
I do recall someone mentioning (or theorising) about a machine
that only had a floating point unit that implemented integers
using a non-normalised representation. The exponent would simply
be padding bits. (...and UINT_MAX would equal INT_MAX.)

IIRC[*] it was a Burroughs machine of 1960's vintage.
You could pass integers and floating-point values around
interchangeably; words with all-zero exponent fields were
integers, others were F-P.

I don't recall further details of the representations,
nor whether there was a distinction between signed and
unsigned arithmetic. This was all pre-C, in any case; the
thing that caught my eye was that in this machine's FORTRAN
it was not an error to pass an integer value to a subroutine
expecting F-P, or vice versa.

[*] By no means a sure bet. I recall reading about the
machine, but I never actually used or wrote programs for it.
 
T

Tim Rentsch

Eric Sosman said:
It's from ISO/IEC 9899:1999(E), the original C99. I admit
I haven't kept up with the post-2000 updates.

The real issue, though, isn't the circumstances under which
exact-width types are required, but your contention that all
integer types must use the same scheme (two's complement,
ones' complement, or signed magnitude). I brought up the exact-
width stuff as a gentle way of ridiculing the contention; can
you find any actual support for it?

The language in 6.2.6.2p2, talking about signed integer types,
clearly is talking about the signed integer types as a group.
Notice the last subparagraph (the one that starts "Which of these
applies is implementation-defined..."). ISTM that there is less
strain in the writing if this is interpreted as applying to all
signed integer types as a group rather than as a separate decision
for each individual type. Certainly it would have been easy to
say "... is implementation-defined for each type ..." if that had
been the intention. But the text doesn't say that.

Also, notice the wording in 6.2.6.2p3 and p4. "If the implementation
supports negative zeros ..." and "If the implementation does not
support negative zeros ...". Pretty clearly this wording reflects an
expectation that supporting or not supporting negative zeros is an
implementation-wide decision, not a per-type decision. But negative
zeros are first discussed in that same last subparagraph of 6.2.6.2p2
just mentioned. It doesn't make sense that negative zeros should be
an implementation-wide decision but the choice of 2's complement, 1's
complement, or s/m, should be a per-type decision.
 
P

Phil Carmody

Squeamizh said:
Read again. He said he's never seen one's complement or sign-magnitude
in the real world. That has nothing to do with floating point.

The real world has nothing to do with floating point?

Woh - you've never worked as a DSP programmer.

PHil
 
P

Phil Carmody

Eric Sosman said:
[...]
I do recall someone mentioning (or theorising) about a machine
that only had a floating point unit that implemented integers
using a non-normalised representation. The exponent would simply
be padding bits. (...and UINT_MAX would equal INT_MAX.)

IIRC[*] it was a Burroughs machine of 1960's vintage.
You could pass integers and floating-point values around
interchangeably; words with all-zero exponent fields were
integers, others were F-P.

Not just the 60s. In the 90s I encountered an architecture
with no ints, and nothing unsigned. Everything was either a
signed floating point value, or a pointer. The superficially
simplest things required quite a bit of hoop jumping (all
done by the C compiler, obviously), but for convolutions
its muladd piplines were the bee's knees.

Phil
 
T

Tim Rentsch

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.

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.

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.


[*] 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.

As I said, it doesn't seem terribly likely.

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.
 
B

Ben Bacarisse

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.

I don't get this part. The bit pattern that /might/ be a negative
zero is either a trap representation or it is a normal value; in which
case it is called negative zero (6.2.6.2 p2). I don't see how signal
handling applies to negative zero. This is an argument about terms,
but they seem to be important ones.

<snip>
 
K

Keith Thompson

Phil Carmody said:
The real world has nothing to do with floating point?

Nobody said that, or anything resembling it.

The point, I think, is that, even though floating-point formats
typically have a sign bit similar to the one in a sign-and-magnitude,
integer representation, the term "sign-and-magnitude" typically refers
only to signed integers.

It's obvious what Joe and Squeamizh meant unless you choose to
deliberately misinterpret it.
 
K

Keith Thompson

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top