[comp.lang.c] Is #define THING -10 completely safe?

rtm@christmas.UUCP (Richard Minner) (01/25/91)

In article <1991Jan23.015757.22220@portia.Stanford.EDU> fangchin@portia.Stanford.EDU (Chin Fang) writes:
>... from my /usr/include/limits.h
>#define INT_MIN     -2147483648  /* min decimal value of an "int" */

Something I've been curious about, should the above be
#define INT_MIN   (-2147483648)

The precedence rules seem to imply that ()'s aren't needed
with a negative integer constant.  Could someone confirm or
deny this please?  (I always use ()'s out of habit.)
-- 
Richard Minner  rtm@island.COM  {uunet,sun,well}!island!rtm
Island Graphics Corporation  Sacramento, CA  (916) 736-1323

ccplumb@rose.uwaterloo.ca (Colin Plumb) (01/28/91)

rtm@island.COM (Richard Minner) wrote:
>> #define INT_MIN     -2147483648  /* min decimal value of an "int" */
>
> Something I've been curious about, should the above be
> #define INT_MIN   (-2147483648)
>
> The precedence rules seem to imply that ()'s aren't needed
> with a negative integer constant.  Could someone confirm or
> deny this please?  (I always use ()'s out of habit.)

Well, unary - has higher precedence than anything except the postfix
opertors:
[expression]
(argument-list)
.identifier
->identifier
++
--

Now, none of these are applicable to intergers, so it's safe... except!
As all loyal followers of the Obfuscated C code contest know,
array[i] == *(array+i) == *(i+array) == i[array].  So

#define X1 -10
#define X2 (-10)
int i, foo[50];
int *p = &foo[25];

for (i = 0; i < 50; i++)
	foo[i] = i;

printf("%d, %d\n", X1[p], X2[p]);

Will print "-35, 15".

If onbody's used this particular perversion in the obfuscated C code contest
yet, I'm sure they will soon.
-- 
	-Colin

gwyn@smoke.brl.mil (Doug Gwyn) (01/28/91)

In article <33@christmas.UUCP> rtm@island.COM (Richard Minner) writes:
>Something I've been curious about, should the above be
>#define INT_MIN   (-2147483648)

Yes.

>The precedence rules seem to imply that ()'s aren't needed
>with a negative integer constant.

There are contexts that could cause trouble, e.g. "x-INT_MIN"
or "x=INT_MIN".  While the C standard requires that these work
as expected, many older C implementations will misinterpret
these.

gwyn@smoke.brl.mil (Doug Gwyn) (01/28/91)

In article <1991Jan27.233142.28302@watdragon.waterloo.edu> ccplumb@rose.uwaterloo.ca (Colin Plumb) writes:
-As all loyal followers of the Obfuscated C code contest know,
-array[i] == *(array+i) == *(i+array) == i[array].  So
-#define X1 -10
-#define X2 (-10)
-[...]
-printf("%d, %d\n", X1[p], X2[p]);
-Will print "-35, 15".

No, that's a ludicrous misinterpretation of the situation.  The
compiler does NOT perform a textual "rewrite" of the [] expression
then reparse it.

dave@cs.arizona.edu (Dave P. Schaumann) (01/28/91)

In article <14999@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
|In article <1991Jan27.233142.28302@watdragon.waterloo.edu> ccplumb@rose.uwaterloo.ca (Colin Plumb) writes:
|-As all loyal followers of the Obfuscated C code contest know,
|-array[i] == *(array+i) == *(i+array) == i[array].  So
|-#define X1 -10
|-#define X2 (-10)
|-[...]
|-printf("%d, %d\n", X1[p], X2[p]);
|-Will print "-35, 15".
|
|No, that's a ludicrous misinterpretation of the situation.  The
|compiler does NOT perform a textual "rewrite" of the [] expression
|then reparse it.


This works as Colin says on my machine (compiling with gcc).  Here is the
full program:

#include <stdio.h>

#define X1  -10
#define X2 (-10)

main(void) {

  int i, a[50], *p = &a[25] ;

  for( i = 0 ; i < 50 ; i++ ) a[i] = i ;

  printf( "X1:%d X2:%d", X1[p], X2[p] ) ;

}

If Colin's interpretation is wrong, what *is* happening?

Dave Schaumann		|  And then -- what then?  Then, future...
dave@cs.arizona.edu	|  		-Weather Report

krey@i30fs1.ira.uka.de (Andreas Krey) (01/29/91)

In article <745@caslon.cs.arizona.edu>, dave@cs.arizona.edu (Dave P.
Schaumann) writes:
> In article <14999@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
> |In article <1991Jan27.233142.28302@watdragon.waterloo.edu>
ccplumb@rose.uwaterloo.ca (Colin Plumb) writes:
> |-As all loyal followers of the Obfuscated C code contest know,
> |-array[i] == *(array+i) == *(i+array) == i[array].  So
> |-#define X1 -10
> |-#define X2 (-10)
> |-[...]
> |-printf("%d, %d\n", X1[p], X2[p]);
> |-Will print "-35, 15".
> |
> |No, that's a ludicrous misinterpretation of the situation.  The
> |compiler does NOT perform a textual "rewrite" of the [] expression
> |then reparse it.
> 
> 
> This works as Colin says on my machine (compiling with gcc).  Here is the
> full program:
>
[ program deleted ] 
> 
> If Colin's interpretation is wrong, what *is* happening?
> 
> Dave Schaumann		|  And then -- what then?  Then, future...
> dave@cs.arizona.edu	|  		-Weather Report

'X1[p]' -> preprocessor -> '-10[p]'
That is, by precedence rules, the same as '-(10[p])', same as '-(p[10])',
which is 35 in the program above.

The latter conversions are no textual 'rewrites'; the compiler simply reduces
the a[b] first, then the -a. Thus array reference goes before negation
and there
is the negative sign. X2 on the other hand is parsed differently because of the
braces around -10. (The [] is actually a commutative operator, although the 
concrete syntax may suggest otherwise.)

Besides I nearly always brace all replacement texts with more than one token 
and all macro parameters within them, just to be sure.

.signature: No such file or directory

gwyn@smoke.brl.mil (Doug Gwyn) (01/29/91)

In article <745@caslon.cs.arizona.edu> dave@cs.arizona.edu (Dave P. Schaumann) writes:
>If Colin's interpretation is wrong, what *is* happening?

What I assumed Colin was blaming the difference on was the rewrite rule,
which is not the source of the difference.  -10[p] and (-10)[p] are not
the same due to [] having higher precedence than -.  Colin's is another
(this time strictly conforming) example illustrating that the parentheses
in the macro definition DO matter.  If that's what he intended to say,
I apologize for misunderstanding.

lwj@cs.kun.nl (Luc Rooijakkers) (01/29/91)

In <14998@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:

>In article <33@christmas.UUCP> rtm@island.COM (Richard Minner) writes:
>>Something I've been curious about, should the above be
>>#define INT_MIN   (-2147483648)

>Yes.

This may have been the intention of the comittee. However, I cannot find
such a guarantee:

	2.2.4.2 Sizes of Integral Types <limits.h>

	The values given below shall be replaced by constant expressions
	suitable for use in #if preprocessing directives.
	
Now, an expression like -2147483648 certainly satisfies the above
constraints.

>>The precedence rules seem to imply that ()'s aren't needed
>>with a negative integer constant.

>There are contexts that could cause trouble, e.g. "x-INT_MIN"
>or "x=INT_MIN".  While the C standard requires that these work
>as expected, many older C implementations will misinterpret
>these.

Right. As has been pointed out already, however, there are also contexts
that can cause trouble where the standard requires it, e.g.

	INT_MIN[p]

which expands to

	-2147483648[p]

which is equivalent to

	-(2147483648[p])

Thus, I would conclude that INT_MIN cannot be used in this way in a
strictly conforming program. Instead, 

	(INT_MIN)[p]
	
would have to be used.

(This is an obscure corner of the language, I agree.)

--
Luc Rooijakkers                                 Internet: lwj@cs.kun.nl
Faculty of Mathematics and Computer Science     UUCP: uunet!cs.kun.nl!lwj
University of Nijmegen, the Netherlands         tel. +3180652271

debra@svin02.info.win.tue.nl (Paul de Bra) (01/29/91)

In article <33@christmas.UUCP> rtm@island.COM (Richard Minner) writes:
>In article <1991Jan23.015757.22220@portia.Stanford.EDU> fangchin@portia.Stanford.EDU (Chin Fang) writes:
>>... from my /usr/include/limits.h
>>#define INT_MIN     -2147483648  /* min decimal value of an "int" */

As James Clark reminded me a long time ago,
-2147483648 is a (constant) expression, not evaluated by the preprocessor
but by the compiler. This has 2 implications:
1) as people have said before, the replacement is purely textual, so the
   unary minus can be misused as a binary minus when writing something
   like 5 INT_MIN
2) this define is not supposed to work at all if 2147483648 is not a legal
   positive integer. (on most machines it isn't)
   if INT_MAX is 2147483647 then INT_MIN should not be written as
   -2147483648 but as (-2147483647-1)
   so your limits.h is at fault, and some compilers (including gcc)
   will not treat your INT_MIN as a large negative number, because
   of integral promotion. (2147483648 is promoted to unsigned because
   it is too large for a signed int)

Paul.
(debra@win.tue.nl, debra@research.att.com)

gwyn@smoke.brl.mil (Doug Gwyn) (01/30/91)

In article <2698@wn1.sci.kun.nl> lwj@cs.kun.nl (Luc Rooijakkers) writes:
>In <14998@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>>In article <33@christmas.UUCP> rtm@island.COM (Richard Minner) writes:
>>>Something I've been curious about, should the above be
>>>#define INT_MIN   (-2147483648)
>>Yes.
>This may have been the intention of the comittee.

I wasn't trying to interpret the intention of X3J11; the fellow asked
whether the implementation "should" parenthesize such definitions, and
I said "Yes".  I would hope that implementors would do so, and that
programmers would not write INT_MIN[p] in their code.

nathan@elberton.inmos.co.uk (Nathan Sidwell) (01/31/91)

In article <14998@smoke.brl.mil> gwyn@smoke.brl.mil (Doug Gwyn) writes:
>In article <33@christmas.UUCP> rtm@island.COM (Richard Minner) writes:
>>Something I've been curious about, should the above be
>>#define INT_MIN   (-2147483648)
>
>Yes.
>
>>The precedence rules seem to imply that ()'s aren't needed
>>with a negative integer constant.
>
>There are contexts that could cause trouble, e.g. "x-INT_MIN"
>or "x=INT_MIN".  While the C standard requires that these work
>as expected, many older C implementations will misinterpret
>these.

Well gcc -ansi doesn't, 
source is

#define NUM -10
main()
{
  int x;
  x = x-NUM;
  x = 1/**/2;
}

preprocessor output is

main()
{
  int x;
  x = x--10;
  x = 1 2;
}

which fails, note that it is partly correct as
the /**/ has been reduced to a space. This is gcc 1.36, has it been
fixed in later versions?

Nathan Sidwell, INMOS Ltd, UK         JANET:    nathan@uk.co.inmos
Generic disclaimer applies            UUCP:     ukc!inmos!nathan
This space unintentionally filled     INTERNET: nathan@inmos.com

torek@elf.ee.lbl.gov (Chris Torek) (02/14/91)

In article <1702@svin02.info.win.tue.nl> debra@svin02.info.win.tue.nl
(Paul de Bra) writes:
>   if INT_MAX is 2147483647 then INT_MIN should not be written as
>   -2147483648 but as (-2147483647-1)

Paul is correct here.  The type and value of -2147483648 are unsigned long
and 2147483648 respectively (on a typical two's complement 32-bit machine).
The constant is made up of two subexpressions, namely unary minus and
the integral constant `2147483648', and the latter is an unsigned long.
Negation does not alter the type, and in this particular case it leaves
the value unchanged as well.

>-2147483648 is a (constant) expression, not evaluated by the preprocessor
>but by the compiler.

Actually, it is at times evaulated by both.  The preprocessor has
arithmetic that is similar to, but not the same as, that in the
compiler.  When I discovered this I raised a very minor fuss (a
fusslet? fusslette? :-) ) since it complicates the preprocessor, which
must understand unsigned values (including U-suffixed constants):

	#include <stdio.h>

	void a() {
	#if -1 > 1
		printf("bad\n");
	#else
		printf("good\n");
	#endif
	}

	void b() { 
	#if -1U > 1
		printf("good\n");
	#else
		printf("bad\n");
	#endif
	}

	int main() { a(); b(); return 0; }

must print `good' twice.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov