Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

int and unsigned int

260 views
Skip to first unread message

Andrei Alexandrescu

unread,
Nov 7, 2002, 10:08:00 PM11/7/02
to
Given two ints i1 and i2, if i1 == i2, does it follow that the
relationship
below is also true?

*reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
int*>(&i2)

and conversely, if i1 != i2, does it follow that

*reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
int*>(&i2)

is true?


Andrei

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Hillel Y. Sims

unread,
Nov 8, 2002, 10:45:34 AM11/8/02
to
"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:aqenu8$8b6i5$1...@ID-14036.news.dfncis.de...

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

5.2.10 Reinterpret cast [expr.reinterpret.cast]

3 The mapping performed by reinterpret_cast is implementation-defined.
[Note: it might, or might not, produce a representation different from
the original value. ]

But is this relevant here?
11An lvalue expression of type T1 can be cast to the type "reference to
T2" if an expression of type "pointer to T1" can be explicitly con-
verted to the type "pointer to T2" using a reinterpret_cast. That is,
a reference cast reinterpret_cast<T&>(x) has the same effect as the
conversion *reinterpret_cast<T*>(&x) with the built-in & and * opera-
tors. The result is an lvalue that refers to the same object as the
source lvalue, but with a different type. No temporary is created, no
copy is made, and constructors (_class.ctor_) or conversion functions
(_class.conv_) are not called.


hys

--
Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

Anthony Williams

unread,
Nov 8, 2002, 10:48:42 AM11/8/02
to
"Andrei Alexandrescu" <andre...@hotmail.com> writes:

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

For both cases, practically: yes, theoretically: no. The only thing you
can do
with a reinterpret_cast'ed pointer is cast it back again, _unless_ the
result
is a pointer to unsigned char, in which case you can use it to look at
the
underlying byte representation of the object, if the original is POD.
But you
knew all that already.

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

Ken Hagan

unread,
Nov 8, 2002, 12:42:46 PM11/8/02
to
"Andrei Alexandrescu" <andre...@hotmail.com> wrote...

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

How about a sign/magnitude representation?

unsigned pos = 0x0000; // positive zero
unsigned neg = 0x8000; // negative zero
assert( *(int*)&pos == *(int*)&neg ); // both "zero"

(Disclaimer: I've never used S+M machines, and I hope never have to.)

James Kanze

unread,
Nov 8, 2002, 1:28:35 PM11/8/02
to
"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:<aqenu8$8b6i5$1...@ID-14036.news.dfncis.de>...

> Given two ints i1 and i2, if i1 == i2, does it follow that the


> relationship below is also true?

> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)

No, not necessarily. It probably won't hold true on a machine with
signed magnitude or 1's complement, if i1 and i2 are zeros with
different signs.

> and conversely, if i1 != i2, does it follow that

> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)

> is true?

I doubt that there is anything in the standard which will guarantee it,
but I can't come up with a representation where it would not hold.
Alghough... is there a requirement that UINT_MAX be greater than
INT_MAX? On a machine with no other support for unsigned types, could
the implementation simply use signed types and ignore the sign bit?

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

Ron Natalie

unread,
Nov 8, 2002, 1:31:49 PM11/8/02
to

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:aqenu8$8b6i5$1...@ID-14036.news.dfncis.de...
> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
Only when i1 and i2 contain positive values.

Maciej Sobczak

unread,
Nov 8, 2002, 1:39:52 PM11/8/02
to
Hi,

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:aqenu8$8b6i5$1...@ID-14036.news.dfncis.de...

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

My reading of 3.9.1/ 1,3,7 is that the implementation which uses:
- 2's compliment for int - say, n bits, where nonnegative values occupy
only
lowest n-1 bits
- "pure" binary n-1 bits for unsigned int, with the constraint that the
highest bit in the n-bit word is always 0

is conformant.

In other words, the implementation where unsigned int has the same range
as
nonnegative values of int (but no more) is conformant.

In other words, unsigned int is guaranteed to cover the nonnegative
values
of int, but is not guaranteed to have enough information capacity to
cover
anything more (see 3.9.1/3).

That means, your code can go astray with UB, if ints are negative, since
their bit patterns can have no meaning when interpreting them as
unsigned
int.

I may be wrong, see 3.9.1/4, which say that unsigned int should obey the
modulo 2^n arithmetic, where n is the number of bits in the value
representation of that particular size of INTEGER (emphasis added). I do
not
know, if authors wanted to say INTEGER or maybe UNSIGNED INTEGER. I
think
that the latter was the intent.

Cheers,

--
Maciej Sobczak
http://www.maciejsobczak.com/

rishi

unread,
Nov 8, 2002, 1:41:50 PM11/8/02
to
Sure
there is one-to-one mapping between the unsigned integers and signed
ones.
rishi

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:<aqenu8$8b6i5$1...@ID-14036.news.dfncis.de>...

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)
>
> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Andrei Alexandrescu

unread,
Nov 8, 2002, 9:02:42 PM11/8/02
to
"Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message
news:aqg29c$e1s$1$8300...@news.demon.co.uk...

> How about a sign/magnitude representation?
>
> unsigned pos = 0x0000; // positive zero
> unsigned neg = 0x8000; // negative zero
> assert( *(int*)&pos == *(int*)&neg ); // both "zero"
>
> (Disclaimer: I've never used S+M machines, and I hope never have to.)

I recall C and C++ require a two's complement representation of
integers.
Right?

Andrei

Ron Natalie

unread,
Nov 8, 2002, 10:21:04 PM11/8/02
to

"rishi" <ris...@geometricsoftware.com> wrote in message
news:d212d6c.02110...@posting.google.com...

> Sure
> there is one-to-one mapping between the unsigned integers and signed
> ones.
> rishi

Only for the positive values.

Nikolai Borissov

unread,
Nov 8, 2002, 10:25:03 PM11/8/02
to

Andrei Alexandrescu wrote :

> Given two ints i1 and i2, if i1 == i2, does it follow that the
> relationship
> below is also true?
>
> *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> int*>(&i2)

As already was noted by other posters it may not be true on machines
with
one's compliment and sign-magniture representations of integers, because
0
can be represented differently as -0 and +0 on those machines. However,
I
think, zero result of normal arithmetic operation on those machines is
always +0, and -0 may appear as a result of overflow only. Then the
following statement may be true:

int j1 = i1+0;
int j2 = i2+0;

if i1 == i2 then
*reinterpret_cast<unsigned int*>(&j1) == *reinterpret_cast<unsigned
int*>(&j2)

> and conversely, if i1 != i2, does it follow that
>
> *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> int*>(&i2)
>
> is true?

This is certainly true. if i1!=i2 then its bit representation must be
different, hence reinterpret_cast to unsigned will yield different
values.

Nikolai Borissov

P.J. Plauger

unread,
Nov 9, 2002, 11:27:40 AM11/9/02
to
"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:H59r0...@beaver.cs.washington.edu...

> "Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message
> news:aqg29c$e1s$1$8300...@news.demon.co.uk...
> > How about a sign/magnitude representation?
> >
> > unsigned pos = 0x0000; // positive zero
> > unsigned neg = 0x8000; // negative zero
> > assert( *(int*)&pos == *(int*)&neg ); // both "zero"
> >
> > (Disclaimer: I've never used S+M machines, and I hope never have
to.)
>
> I recall C and C++ require a two's complement representation of
> integers.
> Right?

Wrong. They permit at least ones complement, twos complement, and
signed magnitude.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com

John Potter

unread,
Nov 9, 2002, 11:30:29 AM11/9/02
to
On 8 Nov 2002 21:02:42 -0500, "Andrei Alexandrescu"
<andre...@hotmail.com> wrote:

> I recall C and C++ require a two's complement representation of
> integers.

> Right?

Wrong. 3.9.1/7

John

Ron Natalie

unread,
Nov 9, 2002, 5:49:18 PM11/9/02
to

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message news:H59r0...@beaver.cs.washington.edu...

>


> I recall C and C++ require a two's complement representation of
> integers.
> Right?

Wrong.

The requirement is that if you convert a negative number to unsigned that
it converts as if it is 2's complement (regardless of what the underlying
signed integer format is). For example:

int i = -1;
unsigned u = i;

u must then be all 1's. It's quite legal for int i to be encoded in 1's
complmeent: FFFE for example

John Potter

unread,
Nov 9, 2002, 9:00:20 PM11/9/02
to
On 9 Nov 2002 17:49:18 -0500, "Ron Natalie" <r...@sensor.com> wrote:

> The requirement is that if you convert a negative number to unsigned that
> it converts as if it is 2's complement (regardless of what the underlying
> signed integer format is). For example:

> int i = -1;
> unsigned u = i;

> u must then be all 1's. It's quite legal for int i to be encoded in 1's
> complmeent: FFFE for example

There also seems to be a restriction on the non-negative values. They
must have the same bit pattern in both signed and unsigned. This
prevents using excess-2^15 for int16. Or am I misreading that?

John

Maciej Sobczak

unread,
Nov 10, 2002, 10:44:52 AM11/10/02
to
Hi,

"Ron Natalie" <r...@sensor.com> wrote in message
news:bbbz9.605688$nE3.4...@atlpnn01.usenetserver.com...


> The requirement is that if you convert a negative number to unsigned that
> it converts as if it is 2's complement (regardless of what the underlying
> signed integer format is). For example:
>
> int i = -1;
> unsigned u = i;
>
> u must then be all 1's.

Could you please throw some paragraph numbers to support this?
I cannot deduce this requirement from the parts of the Standard mentioned in
other posts. My understanding is that negative ints are *not* required to be
representable in *any* way as unsigned int.

Cheers,

Shannon Barber

unread,
Nov 10, 2002, 2:35:17 PM11/10/02
to
"Ken Hagan" <K.H...@thermoteknix.co.uk> wrote:
>
> How about a sign/magnitude representation?
>
> unsigned pos = 0x0000; // positive zero
> unsigned neg = 0x8000; // negative zero
> assert( *(int*)&pos == *(int*)&neg ); // both "zero"
>
> (Disclaimer: I've never used S+M machines, and I hope never have to.)
>
There is no negative zero, the integers are stored as two's
complement. If only the msb is set, it represents the largest
negative number that it can represent. e.g. for 32bit integers, this
is -2147483648. Great pains were taken to avoid that redundancy.

Do you think we could convince the community to stop calling them
integers, and start calling them rings? signed ring -> int, |long
ring| >= |ring|

rishi

unread,
Nov 10, 2002, 5:59:50 PM11/10/02
to
ohh i meant that each signed integer corresponds to a unsigned
integer. This does not mean that they both have the same value
representation. If we assume that the unsigned integer has at least as
many bits as the signed ones and we
are using 2's complement arithmetic then i can't think why there
should be any thing wrong with the relational operations. The signed
to unsigned conversion must be acting equally on both the left operand
and the right operand so why do
you think it will not work for certain cases...
can you give an example
thanks
rishi

"Ron Natalie" <r...@sensor.com> wrote in message news:<4_Ty9.591295$nE3.2...@atlpnn01.usenetserver.com>...

John Potter

unread,
Nov 10, 2002, 11:13:51 PM11/10/02
to
On 10 Nov 2002 10:44:52 -0500, "Maciej Sobczak"
<mac...@maciejsobczak.com> wrote:

> "Ron Natalie" <r...@sensor.com> wrote in message
> news:bbbz9.605688$nE3.4...@atlpnn01.usenetserver.com...
> > The requirement is that if you convert a negative number to unsigned
that
> > it converts as if it is 2's complement (regardless of what the
underlying
> > signed integer format is). For example:

> > int i = -1;
> > unsigned u = i;

> > u must then be all 1's.

> Could you please throw some paragraph numbers to support this?
> I cannot deduce this requirement from the parts of the Standard
mentioned in
> other posts. My understanding is that negative ints are *not* required
to be
> representable in *any* way as unsigned int.

3.9.1/4 unsigned behaves modulo bit size. -1 is one less than 0 which
is all 1 bits. 4.7/2 conversion from signed to unsigned is modulo bit
size. 4.7/3 going the other way is implementation defined if the
unsigned exceeds max signed.

John

John Potter

unread,
Nov 10, 2002, 11:14:46 PM11/10/02
to
On 10 Nov 2002 14:35:17 -0500, shannon...@myrealbox.com (Shannon
Barber) wrote:

> "Ken Hagan" <K.H...@thermoteknix.co.uk> wrote:

> > How about a sign/magnitude representation?

> > unsigned pos = 0x0000; // positive zero
> > unsigned neg = 0x8000; // negative zero
> > assert( *(int*)&pos == *(int*)&neg ); // both "zero"

> > (Disclaimer: I've never used S+M machines, and I hope never have
to.)

> There is no negative zero, the integers are stored as two's
> complement. If only the msb is set, it represents the largest
> negative number that it can represent. e.g. for 32bit integers, this
> is -2147483648. Great pains were taken to avoid that redundancy.

You live in a sheltered world. I have used signed magnitude machines.
The C++ standard supports signed magnitude and signed one's complement
where negative zero is alive and well. The above number does not
exist in these systems. It must be a figment of your two's complement
imagination.

John

Shannon Barber

unread,
Nov 10, 2002, 11:15:24 PM11/10/02
to
"P.J. Plauger" <p...@dinkumware.com> wrote in message
news:<3dcceb65$0$6647$4c41...@reader0.ash.ops.us.uu.net>...

> "Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
> news:H59r0...@beaver.cs.washington.edu...
>
> > "Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message
> > news:aqg29c$e1s$1$8300...@news.demon.co.uk...
> > > How about a sign/magnitude representation?
> > >
> > > unsigned pos = 0x0000; // positive zero
> > > unsigned neg = 0x8000; // negative zero
> > > assert( *(int*)&pos == *(int*)&neg ); // both "zero"
> > >
> > > (Disclaimer: I've never used S+M machines, and I hope never have
> to.)
> >
> > I recall C and C++ require a two's complement representation of
> > integers.
> > Right?
>
> Wrong. They permit at least ones complement, twos complement, and
> signed magnitude.
>
Doh, I forgot this as well, there's even a Gosperism about it:
http://info.astrian.net/jargon/terms/h/HAKMEM.html

Jack Klein

unread,
Nov 11, 2002, 12:13:56 PM11/11/02
to
On 8 Nov 2002 13:28:35 -0500, ka...@gabi-soft.de (James Kanze) wrote
in comp.lang.c++.moderated:

> "Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
> news:<aqenu8$8b6i5$1...@ID-14036.news.dfncis.de>...
>
> > Given two ints i1 and i2, if i1 == i2, does it follow that the
> > relationship below is also true?
>
> > *reinterpret_cast<unsigned int*>(&i1) == *reinterpret_cast<unsigned
> > int*>(&i2)
>
> No, not necessarily. It probably won't hold true on a machine with
> signed magnitude or 1's complement, if i1 and i2 are zeros with
> different signs.
>
> > and conversely, if i1 != i2, does it follow that
>
> > *reinterpret_cast<unsigned int*>(&i1) != *reinterpret_cast<unsigned
> > int*>(&i2)
>
> > is true?
>
> I doubt that there is anything in the standard which will guarantee
it,
> but I can't come up with a representation where it would not hold.
> Alghough... is there a requirement that UINT_MAX be greater than
> INT_MAX? On a machine with no other support for unsigned types, could
> the implementation simply use signed types and ignore the sign bit?

There is no requirement that UINT_MAX be greater than INT_MAX, in
either C or C++. Paragraph 3 of 3.9.1 precludes UINT_MAX being less
than INT_MAX, but there is no requirement that it be greater. So
there are two problems with the proposed code.

The first is that it accesses the value of an object of type int via
an lvalue of a different type other than unsigned char, undefined
behavior in principle.

The second is that on a system where UINT_MAX == INT_MAX, the bit
pattern of a negative signed int interpreted as an unsigned int could
be what the C99 standard calls a "trap value", that is an illegal bit
pattern that can trap on access.

"On a machine with no other support for unsigned types", an
implementation could merely ignore the sign bit, or it could insist on
the sign bit being clear and trap if it is set.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq

Ron Natalie

unread,
Nov 11, 2002, 1:08:08 PM11/11/02
to

"John Potter" <jpo...@falcon.lhup.edu> wrote in message
news:3dcd9a87...@news.earthlink.net...

> There also seems to be a restriction on the non-negative values. They
> must have the same bit pattern in both signed and unsigned. This
> prevents using excess-2^15 for int16. Or am I misreading that?

Correct. The positive values in C++ must have the same representation
as
the unsigned values. C (1999) goes even farther in it's requirements.
C
specifically limits you to 2's complement, 1's complement, and signed
magnitude representations of integers. It's been 15 years since I used
anything
other than a 2's complment. Just don't trip over too many Univac's
these days.

Ron Natalie

unread,
Nov 11, 2002, 1:08:26 PM11/11/02
to

"rishi" <ris...@geometricsoftware.com> wrote in message
news:d212d6c.02111...@posting.google.com...

> ohh i meant that each signed integer corresponds to a unsigned
> integer. This does not mean that they both have the same value
> representation. If we assume that the unsigned integer has at least as
> many bits as the signed ones and we
> are using 2's complement arithmetic then i can't think why there
> should be any thing wrong with the relational operations.

Because there's no guarantee that there you are using two's complement.
It's quite possible that you are using one's complement or signed
magnitude
and the hardware may silently normalize away negative zero values.

Anthony Williams

unread,
Nov 12, 2002, 11:42:19 AM11/12/02
to
Jack Klein <jack...@spamcop.net> writes:

> There is no requirement that UINT_MAX be greater than INT_MAX, in
> either C or C++. Paragraph 3 of 3.9.1 precludes UINT_MAX being less
> than INT_MAX, but there is no requirement that it be greater. So
> there are two problems with the proposed code.

> The second is that on a system where UINT_MAX == INT_MAX, the bit
> pattern of a negative signed int interpreted as an unsigned int could
> be what the C99 standard calls a "trap value", that is an illegal bit
> pattern that can trap on access.

unsigned types cannot have trap representations, since 3.9.1p4 says they
must
obey arithemtic modulo 2^n where n is the number of bits in their value
representation. It also indirectly implies that UNIT_MAX > INT_MAX
because
signed and unsigned integers must have the same value representation ---
the
bit patterns for negative numbers must be distinct from each other, and
from
those of the positive signed numbers, _and_ the positive signed numbers
must
have the same bit patterns as the corresponding positive unsigned
numbers, so
the bit patterns that correspond to negative signed numbers (and any
trap
representations for signed numbers) must relate to distinct unsigned
values,
which must therefore be greater than INT_MAX, and thus UINT_MAX must be
greater than INT_MAX --- indeed it must be greater than or equal to
INT_MAX+(-INT_MIN), and have the value 2^n-1 where n is the number of
bits in
the value representation=CHAR_BITS*sizeof(unsigned).

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Andrei Alexandrescu

unread,
Nov 12, 2002, 5:39:21 PM11/12/02
to
Ok, my question now is:

How can one detect at compile time whether an int* can be
reinterpret_cast
to an unsigned int* for comparison ('==' and '<=') purposes?


Thanks,

Andrei

James Kanze

unread,
Nov 12, 2002, 5:39:49 PM11/12/02
to
ris...@geometricsoftware.com (rishi) wrote in message
news:<d212d6c.02111...@posting.google.com>...

> ohh i meant that each signed integer corresponds to a unsigned
> integer.

That's still not guaranteed. In fact, it is only possible if both value
sets have the same cardinality. As has already been pointed out, the
standard allows UINT_MAX == INT_MAX. And there have been real
implementations where UINT_MAX == INT_MAX - INT_MIN + 1, i.e. where
unsigned int had one more possible value than signed int.

> This does not mean that they both have the same value
> representation. If we assume that the unsigned integer has at least as
> many bits as the signed ones and we are using 2's complement
> arithmetic then i can't think why there should be any thing wrong with
> the relational operations.

And why should we assume that? The data containers of unsigned int and
int must have the same number of bits, but there is no requirement that
all of the bits are used in unsigned int, nor that all of the possible
representations have different values.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Nov 12, 2002, 5:40:28 PM11/12/02
to
jpo...@falcon.lhup.edu (John Potter) wrote in message
news:<3dcedc64...@news.earthlink.net>...

> On 10 Nov 2002 14:35:17 -0500, shannon...@myrealbox.com (Shannon
> Barber) wrote:
> > "Ken Hagan" <K.H...@thermoteknix.co.uk> wrote:

> > > How about a sign/magnitude representation?

> > > unsigned pos = 0x0000; // positive zero
> > > unsigned neg = 0x8000; // negative zero
> > > assert( *(int*)&pos == *(int*)&neg ); // both "zero"

> > > (Disclaimer: I've never used S+M machines, and I hope never have
> > > to.)

> > There is no negative zero, the integers are stored as two's
> > complement. If only the msb is set, it represents the largest
> > negative number that it can represent. e.g. for 32bit integers,
> > this is -2147483648. Great pains were taken to avoid that
> > redundancy.

> You live in a sheltered world.

Come now. I would wager that the majority of readers under thirty have
never had to work on a signed magnitude machine. In fact, I would wager
that a fair percent of older readers haven't either, although they are
far more likely to be aware of their existance. (The only machine I
ever wrote code for that wasn't 2's complement was an IBM 1401, and that
was decimal arithmetic, and didn't have a C++ compiler at the time.
Probably didn't get one since then (1965), either, since the machine was
already out-dated.)

On the other hand, Unisys sold signed magnitude machines until about two
years ago, and still sells ones complements, I think, so there should be
an odd few, even today, you have to deal with such quaintness.

> I have used signed magnitude machines. The C++ standard supports
> signed magnitude and signed one's complement where negative zero is
> alive and well. The above number does not exist in these systems.

It certainly existed on the Unisys series A. Signed magnitude, but 48
bits (of which 8 had to be 0, or the value would be treated as floating
point).

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Nov 12, 2002, 5:40:47 PM11/12/02
to
"Ron Natalie" <r...@sensor.com> wrote in message
news:<R8Pz9.9926$tx1....@atlpnn01.usenetserver.com>...

> "John Potter" <jpo...@falcon.lhup.edu> wrote in message
> news:3dcd9a87...@news.earthlink.net...

> > There also seems to be a restriction on the non-negative values.
> > They must have the same bit pattern in both signed and unsigned.
> > This prevents using excess-2^15 for int16. Or am I misreading that?

> Correct. The positive values in C++ must have the same representation
> as the unsigned values. C (1999) goes even farther in it's
> requirements. C specifically limits you to 2's complement, 1's
> complement, and signed magnitude representations of integers. It's
> been 15 years since I used anything other than a 2's complment. Just
> don't trip over too many Univac's these days.

If you are talking about the old Univac mainframes, I think compatible
models are still being sold by Unisys. (They stopped making the
Burroughs series A -- a signed magnitude machine -- a few years ago.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

John Potter

unread,
Nov 12, 2002, 5:52:39 PM11/12/02
to
On 12 Nov 2002 11:42:19 -0500, Anthony Williams
<anthony.wil...@anthonyw.cjb.net> wrote:

> unsigned types cannot have trap representations, since 3.9.1p4 says
they
> must
> obey arithemtic modulo 2^n where n is the number of bits in their
value
> representation.

I don't think that prohibits trap representations in their object
representations. See below.

> It also indirectly implies that UNIT_MAX > INT_MAX
> because
> signed and unsigned integers must have the same value representation
---
> the
> bit patterns for negative numbers must be distinct from each other,
and
> from
> those of the positive signed numbers, _and_ the positive signed
numbers
> must
> have the same bit patterns as the corresponding positive unsigned
> numbers, so
> the bit patterns that correspond to negative signed numbers (and any
> trap
> representations for signed numbers) must relate to distinct unsigned
> values,
> which must therefore be greater than INT_MAX, and thus UINT_MAX must
be
> greater than INT_MAX --- indeed it must be greater than or equal to
> INT_MAX+(-INT_MIN), and have the value 2^n-1 where n is the number of
> bits in
> the value representation=CHAR_BITS*sizeof(unsigned).

Sounded good until that =. CHAR_BITS*sizeof(unsigned) is the number
of bits in the object representation but may be larger than the number
of bits in the value representation. Example 64 bit words where
unsigned is represented using only 48 bits. There could be trap
values in those other 16 bits. They would never be set by arithmetic
but could be set by memcpy.

John

Anthony Williams

unread,
Nov 13, 2002, 6:09:59 PM11/13/02
to
jpo...@falcon.lhup.edu (John Potter) writes:

> On 12 Nov 2002 11:42:19 -0500, Anthony Williams
> <anthony.wil...@anthonyw.cjb.net> wrote:
>
> > unsigned types cannot have trap representations, since 3.9.1p4 says
> they
> > must
> > obey arithemtic modulo 2^n where n is the number of bits in their
> value
> > representation.
>
> I don't think that prohibits trap representations in their object
> representations. See below.

> CHAR_BITS*sizeof(unsigned) is the number


> of bits in the object representation but may be larger than the number
> of bits in the value representation. Example 64 bit words where
> unsigned is represented using only 48 bits. There could be trap
> values in those other 16 bits. They would never be set by arithmetic
> but could be set by memcpy.

OK, you're right here --- the requirement that all bits in the object
representation must participate in the value representation is exclusive to
char/signed char/unsigned char.

However, you can never get a trap representation by assignment of one valid
unsigned int to another, nor can you get one by conversion from a signed
int. Also, there can't be a trap representation as part of the value
representation, which is distinct from signed types, and floating point
types.

The only safe thing you can do with memcpy is copy an objects byte
representation to an array of unsigned char, and back to an object of the
original type, in which case you can't get a trap representation. Doing
anything else is inherently unsafe, so the fact that you might get a trap
representation for an unsigned type is largely irrelevant.

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jerry Coffin

unread,
Nov 13, 2002, 6:12:17 PM11/13/02
to
In article <d6651fb6.0211...@posting.google.com>,
ka...@gabi-soft.de says...

[ ... ]

> Come now. I would wager that the majority of readers under thirty have
> never had to work on a signed magnitude machine. In fact, I would wager
> that a fair percent of older readers haven't either, although they are
> far more likely to be aware of their existance. (The only machine I
> ever wrote code for that wasn't 2's complement was an IBM 1401,

....at least for integer types. Many current machines (e.g. the
ubiquitous x86) don't use 2's complement for floating point. I'll
admit I'm a little bit past thirty, but I've written code for 1's
complement and sign/magnitude and a couple of other odd-ball formats
as well (including BCD, though not for an IBM mainframe).

--
Later,
Jerry.

The universe is a figment of its own imagination.

James Kanze

unread,
Nov 13, 2002, 6:27:54 PM11/13/02
to
Anthony Williams <anthony.wil...@anthonyw.cjb.net> wrote in
message news:<d6pbqf...@anthonyw.cjb.net>...
> Jack Klein <jack...@spamcop.net> writes:

> > There is no requirement that UINT_MAX be greater than INT_MAX, in
> > either C or C++. Paragraph 3 of 3.9.1 precludes UINT_MAX being less
> > than INT_MAX, but there is no requirement that it be greater. So
> > there are two problems with the proposed code.

> > The second is that on a system where UINT_MAX == INT_MAX, the bit
> > pattern of a negative signed int interpreted as an unsigned int
> > could be what the C99 standard calls a "trap value", that is an
> > illegal bit pattern that can trap on access.

> unsigned types cannot have trap representations, since 3.9.1p4 says
> they must obey arithemtic modulo 2^n where n is the number of bits in
> their value representation.

In their value representation. There is nothing that says that all bits
must participate in the value representation of an unsigned.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Anthony Williams

unread,
Nov 14, 2002, 8:23:02 AM11/14/02
to
ka...@gabi-soft.de (James Kanze) writes:

> Anthony Williams <anthony.wil...@anthonyw.cjb.net> wrote in
> message news:<d6pbqf...@anthonyw.cjb.net>...

> > unsigned types cannot have trap representations, since 3.9.1p4 says
> > they must obey arithemtic modulo 2^n where n is the number of bits
in
> > their value representation.
>
> In their value representation. There is nothing that says that all
bits
> must participate in the value representation of an unsigned.

Surely the bits that don't participate in the value representation, by
definition don't participate, so are completely irrelevant? If they are
not
irrelevant, surely they must therefore be participating in the value
representation, since they are affecting the value (i.e. whether or not
it
causes a trap).

Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Nov 15, 2002, 12:19:01 PM11/15/02
to
Anthony Williams <anthony.wil...@anthonyw.cjb.net> wrote in
message news:<adkc8n...@anthonyw.cjb.net>...

> ka...@gabi-soft.de (James Kanze) writes:
> > Anthony Williams <anthony.wil...@anthonyw.cjb.net> wrote in
> > message news:<d6pbqf...@anthonyw.cjb.net>...

> > > unsigned types cannot have trap representations, since 3.9.1p4
> > > says they must obey arithemtic modulo 2^n where n is the number of
> > > bits in their value representation.

> > In their value representation. There is nothing that says that all
> > bits must participate in the value representation of an unsigned.

> Surely the bits that don't participate in the value representation, by
> definition don't participate, so are completely irrelevant? If they
> are not irrelevant, surely they must therefore be participating in the
> value representation, since they are affecting the value (i.e. whether
> or not it causes a trap).

The obvious counter-example would be parity bits, which don't affect the
value, but cannot be arbitrary values either. There is (or was)
definitely one machine in which a certain number of bits must be 0.

In both cases, of course, in practice, the same bits will be present in
the signed representation, so they wouldn't come into play in the case
in question. But the standard doesn't forbit a difference here;
presumably, an implementation could used the sign bit in an int as a
parity bit in an unsigned. (According to the standard -- I can't
imagine anything that wierd in reality, and I've seen some pretty wierd
things.)

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Niklas Matthies

unread,
Nov 16, 2002, 9:40:55 AM11/16/02
to
On 12 Nov 2002 17:39:21 -0500, Andrei Alexandrescu

<andre...@hotmail.com> wrote:
> Ok, my question now is:
>
> How can one detect at compile time whether an int* can be
> reinterpret_cast to an unsigned int* for comparison ('==' and '<=')
> purposes?

I think that those comparisons will only be guaranteed to make sense
when you can determine that there is a 1:1 mapping between the int and
unsigned int values. More precisely:

1) both types must have the same set of valid value representations
2) all value representations of a given value of one type must also
be a value representation of exactly one value of the other type

The first criterion is obvious, otherwise a valid value representation
of one type could be a trap representation of the other type.

An example for a violation of the second criterion is an implementation
where unsigned int is simply implemented by ignoring the sign of an int,
(e.g. unsigned 1 can be represented by both signed 1 and signed -1). On
such an implementation,

*reinterpret_cast<unsigned *)(&int1) == *reinterpret_cast<unsigned
*)(&int2)

could evaluated to true although the int objects may hold different
values.
The opposite is also possible:

unsigned int representation: VVV...V
signed int representation: ISV...V

where V = value bit, S = sign bit, I = ignored bit

A simple case where both criteria are met, which also happens to be the
most common one, is when

UINT_MAX = INT_MAX - INT_MIN (eq1)
UINT_MAX = 2 ^ (sizeof(int) * CHAR_BIT) -1 (eq2)

are both true. Preventing overflows when checking those equations is not
trivial, but as far as I can tell the following should be pretty safe:


#include <limits.h>
#include <stddef.h>


template <int i, unsigned int u> class eq1; // forward declaration


#define U(x) (static_cast<unsigned int>(x))


template <bool ii, bool uu, int i, unsigned int u>
struct eq1_helper { enum { result = 0 }; };

template <int i, unsigned int u>
struct eq1_helper<true, true, i, u>
{
enum { result = eq1<i + INT_MAX, u - U(INT_MAX)>::result };
};

template <bool uu, int i, unsigned int u>
struct eq1_helper<false, uu, i, u>
{
enum { result = uu ? u - U(INT_MAX) == U(-i) : U(INT_MAX) - u ==
U(i) };
};


template <int i = INT_MIN, unsigned int u = UINT_MAX>
struct eq1
{
enum { ii = i + INT_MAX < 0 };
enum { uu = u > U(INT_MAX) };
enum { result = eq1_helper<ii, uu, i, u>::result };
};


#undef U


template <unsigned int u = 1, size_t s = sizeof(int), size_t b =
CHAR_BIT>
struct eq2
{
static size_t const ns = s > 1 ? s - 1 : sizeof(int);
static size_t const nb = s > 1 ? b : b - 1;
enum { result = u <= UINT_MAX / 2 ? eq2<u * 2, ns, nb>::result : 0
};
};

template <unsigned int u>
struct eq2<u, 1, 1>
{
enum { result = UINT_MAX - u + 1 == u };
};


#include <iostream>


int main()
{
std::cout << eq1<>::result << eq2<>::result << std::endl;
}

-- Niklas Matthies

Nikolai Borissov

unread,
Nov 16, 2002, 3:27:33 PM11/16/02
to
Andrei Alexandrescu wrote :

> Ok, my question now is:
>
> How can one detect at compile time whether an int* can be
> reinterpret_cast
> to an unsigned int* for comparison ('==' and '<=') purposes?

The best way to obtain a correct result of comparison between 2 int values
is to compare them directly as ints without reinterpreting to unsigned int.
Apparently I'm missing something, right?

Anyways, here're some expressions that can be evaluated at compile time and
help to figure out if reinterpreting is possible and HOW reinterpreted
values should be compared to get a correct result.

#include <limits>

// Template to calculate number of bits occupied by a value of unsigned int
type
template<unsigned int UI>
struct UI_type {enum {bits=UI_type<UI>>1>::bits+1};};
template<>
struct UI_type<0> {enum {bits=0};};

// Check if int & unsigned int types occupy the same number of bits and all
are used in value representation
#define VALUE_EQU_OBJECT \
( UI_type<(unsigned int)-1>::bits == CHAR_BIT*sizeof(unsigned int) && \
CHAR_BIT*sizeof(unsigned int) == CHAR_BIT*sizeof(int) && \
CHAR_BIT*sizeof(int) == UI_type<(unsigned int)INT_MAX>::bits+1 \
)

// These expressions identify int type representation (two's compliment,
one's compliment and sign-magnitude)
// 1 - yes, 0 - no
#define TWOS_COMP (~0==-1)
#define ONES_COMP (~0==0)
#define SIGN_MAGN (~0<-1)

Nikolai Borissov

0 new messages