[comp.sys.mac.programmer] LSC 3 bug with hex constant handling?

perry@key.COM (Perry The Cynic) (06/12/89)

Consider the following code fragment for Lightspeed (aka THINK) C 3.0.2:
	long a, b;
	a = b & ~1;
This clears the least significant bit of b. It works just fine. However,
if I replace the "1" with its hex equivalent, i.e.
	a = b & ~0x1;
then the resulting code uses the constant 0x0000FFFE (rather than 0xFFFFFFFE)
as operand to the "&" operator, resulting in less than satisfactory results.

Question: is this a bug, or am I overlooking something? I think that the
decimal and hex forms of a constant are semantically equivalent. (Also, which
one is the bug? :-)
BTW, using "0x1L" works, as does (of course) "1L".

Thanks
  -- perry
-- 
------------------------------------------------------------------------
Perry The Cynic (Peter Kiehtreiber)		     perry@arkon.key.com
** What good signature isn't taken yet? **	   ...!pacbell!key!perry

gja@etive.ed.ac.uk (A Cunningham) (06/12/89)

In article <861@key.COM> perry@arkon.key.COM (Perry The Cynic) writes:
>Consider the following code fragment for Lightspeed (aka THINK) C 3.0.2:
>	long a, b;
>	a = b & ~1;
>This clears the least significant bit of b. It works just fine. However,
>if I replace the "1" with its hex equivalent, i.e.
>	a = b & ~0x1;
>then the resulting code uses the constant 0x0000FFFE (rather than 0xFFFFFFFE)

	According to K&R page 35 the 0x implies an int type. If ints are 32
bits in this implementation then ~0x1 should be FFFE.

>BTW, using "0x1L" works, as does (of course) "1L".

	This makes the constant long which in a 64 bit implementation is
0xFFFFFFFE. I think however that the size of an int is a machine dependant
thing. 
		Tony
"I think of Sarah. The rest is easy."

Eat
this 
and 
die,
inews

sdh@wind.bellcore.com (Stephen D Hawley) (06/12/89)

In article <861@key.COM> perry@arkon.key.COM (Perry The Cynic) writes:
>This clears the least significant bit of b. It works just fine. However,
>if I replace the "1" with its hex equivalent, i.e.
>	a = b & ~0x1;
>then the resulting code uses the constant 0x0000FFFE (rather than 0xFFFFFFFE)
>as operand to the "&" operator, resulting in less than satisfactory results.
>

From K&R:
"A sequence of digits preceded by 0x or 0X (digit zero) is taken to be a
hexadecimal integer.  ...  A decimal constant whose value exceeds the largest
unsigned machine integer is taken to be a long; an octal or hex constant which
exceeds the largest unsigned machine integer is likewise taken to be long."

This means that the constant is correct as an int, but section 7.8 claims that
& uses the usual arithmetic conversions.  In this case, it should be converted
to a long (section 6.6).

I would say this is a bug.

Steve Hawley
sdh@flash.bellcore.com

pem@cadnetix.COM (Paul Meyer) (06/13/89)

In article <861@key.COM> perry@arkon.key.COM (Perry The Cynic) writes:
>Consider the following code fragment for Lightspeed (aka THINK) C 3.0.2:
>	long a, b;
>	a = b & ~1;
...[vs.]...
>	a = b & ~0x1;
...
>Question: is this a bug, or am I overlooking something? I think that the
>decimal and hex forms of a constant are semantically equivalent.
...
>BTW, using "0x1L" works, as does (of course) "1L".

	Using the hexadecimal form implies an unsigned int, while
using decimal implies a signed int.  (I think this is even K&R (my K&R
is at home), and it's certainly a useful and reasonable convention.)
So when the int value "~1" gets extended to a long, if it is signed it
sign-extends, but if it's not it doesn't.
	signed:		1 => 0x0001
		 	~1 => 0xfffe
		 	(long) ~1 => 0xfffffffe
	unsigned: 	0x1 => 0x0001
			~0x1 => 0xfffe
			(unsigned long) ~0x1 => 0x0000fffe
			(long) (unsigned long) ~0x1 => 0x0000fffe
kapeesh?

	In any case, you're better off using the explicitly long
constant anyway.  Then the compiler isn't resolving any casts for you,
it's just putting in exactly what you tell it.
Paul Meyer                      pem@cadnetix.COM
Daisy/Cadnetix Inc.		{uunet,boulder}!cadnetix!pem
5775 Flatirons Pkwy.            GEnie P.MEYER
Boulder, CO 80301               (303)444-8075x277

wilson@ji.Berkeley.EDU (James E. Wilson) (06/13/89)

In article <16783@bellcore.bellcore.com> sdh@wind.UUCP (Stephen D Hawley) writes:
>In article <861@key.COM> perry@arkon.key.COM (Perry The Cynic) writes:
>>This clears the least significant bit of b. It works just fine. However,
>>if I replace the "1" with its hex equivalent, i.e.
>>	a = b & ~0x1;
>>then the resulting code uses the constant 0x0000FFFE (rather than 0xFFFFFFFE)
>>as operand to the "&" operator, resulting in less than satisfactory results.
>
>From K&R:
>"A sequence of digits preceded by 0x or 0X (digit zero) is taken to be a
>hexadecimal integer.  ...  A decimal constant whose value exceeds the largest
>unsigned machine integer is taken to be a long; an octal or hex constant which
>exceeds the largest unsigned machine integer is likewise taken to be long."
>
>This means that the constant is correct as an int, but section 7.8 claims that
>& uses the usual arithmetic conversions.  In this case, it should be converted
>to a long (section 6.6).
>
>I would say this is a bug.

You missed the point of the above quote from K&R (section 2.4.1).  Decimal
constants are signed integers, but hexadecimal and octal constants are
unsigned integers.  Hence, the result of the expression ~0x1 is the unsigned
integer value 0xFFFE.

You are correct, that this value is then converted to a long via the usual
arithmetic conversions before it is bitwise anded with b.  However, according
to K&R (section 6.5), unsigned values are padded on the left with zeros when
they are converted to long.  Hence, the result of ~0x1 after conversion to
long is 0x0000FFFE.

Thus, the behaviour of LSC, although rather surprising, is technically correct.

For another example, consider the following code fragment (and assume that
	ints are 16 bits and longs are 32 bits):
  long a, b;
  a = b & 0xFFFF;

Clearly, the intent is to store the lower 16 bits of b into a.  And this
is exactly what LSC will do.  If, however, you insist that hexadecimal
constants should be sign extended, then the result would be that all 32 bits
of b are copied into a (since 0xFFFF is first stored as the int -1, then
converted to the long value -1), which is definately not what the programmer
intended.

Hence, in order for the second code example to work correctly in LSC, the first
code example must give a result contrary to what the naive programmer expects.

These subtleties can all be ignored by just remembering to tack on a 'L' to
all constants that are used with long integers.

Jim Wilson    wilson@ernie.Berkeley.EDU   ...!ucbvax!ucbernie!wilson
  Ya nadeyus', chto kogda-nibud' budet mir na zemle.

lippin@spam.berkeley.edu (The Apathist) (06/13/89)

In article <861@key.COM> perry@arkon.key.COM (Perry The Cynic) writes:
>This clears the least significant bit of b. It works just fine. However,
>if I replace the "1" with its hex equivalent, i.e.
>	a = b & ~0x1;
>then the resulting code uses the constant 0x0000FFFE (rather than 0xFFFFFFFE)
>as operand to the "&" operator, resulting in less than satisfactory results.

This is the correct behaviour if hexadecimal constants are taken to be
unsigned -- the unsigned value would not be sign extended in that
case.  Since I don't have a book of C here, I can't tell you whether
hex constants are signed or not, although unsigned seems plausible.
Perhaps someone out there has the reference handy?

					--Tom Lippincott
					  lippin@math.berkeley.edu

    "Don't be silly.  Of course you're a number, just like everyone else"
					--John Chiapetta

garyi@phred.UUCP (Zngu Zna) (06/16/89)

>  Ya nadeyus', chto kogda-nibud' budet mir na zemle.

Ya tozhye.

boone@neptune.uucp (Jeff Boone) (06/17/89)

In article <2627@phred.UUCP> garyi@phred.UUCP (Zngu Zna) writes:
>>  Ya nadeyus', chto kogda-nibud' budet mir na zemle.
>
>Ya tozhye.

Could we please move this to alt.garbled.mess     :-)