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 :-)