Article View: comp.std.c
Article #3644Re: short division question? ( short ) 0x8000 / ( short ) 0xFFFF = ?
From: Mark Brader
Date: Thu, 03 Aug 1995 16:54
Date: Thu, 03 Aug 1995 16:54
98 lines
4632 bytes
4632 bytes
Clem Taylor (ctaylor@stimpy.eecis.udel.edu) writes:
> main ( )
> {
> short a = 0x8000, b = 0xFFFF, c; /* signed 16 bit values */
> int ia, ib, ic; /* signed 32 bit values */
The constants 0x8000 and 0xFFFF have the values 32768 and 65535 respect-
ively, and on a machine where int is 32 bits, their type is int. [See
section 6.1.3.2/3.1.3.2.] If short is 16 bits, the values cannot be
represented in the type; an implementation-defined conversion then occurs.
[6.5.7/3.5.7, 6.3.16.1/3.3.16.1, and 6.2.1.2/3.2.1.2]
In practice this conversion is typically done by copying the 16 low bits,
so that on a 2's complement machine we get -32768 for a and -1 for b,
but I don't believe there's anything in the standard that requires it to
be implemented in any particular way. However, from here on I will assume
that the values *are* -32768 and -1.
> c = a / b;
The values of a and b are automatically promoted back to int [6.2.1.1/
3.2.1.1], which is then the type of the result of the / operator
[6.2.1.5/3.2.1.5]. Since -32768 is exactly divisible by -1, and the
result of 32768 is representable in the type int, the division must
yield this value.
On the assignment to c, the value is converted back to short [6.3.16.1/
3.3.16.1]; since 32768 cannot be represented in a 16-bit short, the result
is again implementation-defined [6.2.1.2/3.2.1.2]. (Note: this is *not*
a case of undefined behavior. Undefined behavior is caused by on overflow
during arithmetic [6.3/3.3], but type conversion is not an arithmetic
operation.) Since we assumed above that 32768 would convert to -32768,
this applies again and so this value is stored in c.
> printf ( "%d = %d / %d\n", c, a, b );
The values of c, a, and b are each promoted to int before printing
[6.2.1.1/3.2.1.1], which leaves their values unchanged. Under the
assumptions already given, the output will indeed be
> -32768 = -32768 / -1
as cited.
> ia = a;
> ib = b;
> ic = ia / ib;
>
> printf ( "%d = %d / %d\n", ic, ia, ib );
Here we are doing everything in ints, so there is no problem of overflow
and we naturally get the cited
> 32768 = -32768 / -1
Fine.
> However, on one machine that I work on c gets 0x7FFF (32767). So, my
> question is does the standard define this behavior?
The two places where the program causes implementation-defined behavior
are in the conversions of the hexadecimal initializers, and of the result
of the divisions, from int to short. If the int value 32768 yields the
the short value -32768 in one place, it should do so in the other [*].
If Clem's statement that "c gets 0x7FFF (32767)" means that b is -1 but
a and c are unequal, so that the first line printed is
32767 = -32768 / -1
, then the implementation is wrong. [*]
However, it would also be technically legitimate for 32768 to be converted
to -32767 in the initialization of c, while 65535 still becomes -1.
(I think the standard is wrong to allow this, but as noted above, it
merely says that the conversion is implementation-defined if the result
does not fit.) In that case, the result of the division would obviously
be 32767, the output line being
32767 = -32767 / -1
Another variation would be likely on a 1's complement machine, where we
would expect 65535 and 32768 to be converted to 0 and -32767 respectively;
this is unquestionably legitimate. Since the division by 0 is not
mathematically valid, the result of / operators is then undefined
behavior [6.3/3.3], so *anything* can happen after that [3.16/1.6] --
including, in theory, printf() displaying values different from those
passed to it.
[*] There is a little bit of looseness in the standard in that it doesn't
say that the implementation-defined conversions must always yield the same
result for the same value. As far as I know, this has not been the subject
of an official ruling, but it seems clear to me that the intent is that it
should -- the consequences otherwise would be ridiculous.
--
Mark Brader, msb@sq.com | "An actual human would feel guilt in this situation."
SoftQuad Inc., Toronto | -- Scott Adams: Dilbert
This article is in the public domain.
Technical Details
Message-ID:
<1995Aug3.165450.5750@sq.sq.com>Path:
arc1-ca.pugleaf.net!spool.mu.edu!torn!sq!msbReferences:
<3vqpv8$fo0@louie.udel.edu>Show Full Headers
Complete Article Headers
Newsgroups: comp.std.c Path: arc1-ca.pugleaf.net!spool.mu.edu!torn!sq!msb From: msb@sq.sq.com (Mark Brader) Subject: Re: short division question? ( short ) 0x8000 / ( short ) 0xFFFF = ? Message-ID: <1995Aug3.165450.5750@sq.sq.com> Organization: SoftQuad Inc., Toronto, Canada References: <3vqpv8$fo0@louie.udel.edu> Date: Thu, 3 Aug 95 16:54:50 GMT