[comp.unix.questions] Brain-dead Unix tutor needs quick help

alen@cogen.UUCP (Alen Shapiro) (11/18/87)

References:


I'm giving a series of informal Unix/C tutorial sessions (fun - honest).
One of the topics touches on good C coding practices. I've hit a mental
block about the reason ()s are used in preprocessor expressions like
#define XXX (-1). I seem to remember finding the reason absolutely
obvious when I found out about it some years ago but since then it has become
an "obvious" fact of coding, so obvious that I can't remember why.

Please someone out in net-land, put me out of my mysery. Is there a potential
confusion of unary minus with something else here?

--alen the Lisa slayer (it's a long story)

mohamed@hscfvax.UUCP (750025@Mohamed_el_Lozy) (11/18/87)

In article <387@cogen.UUCP> alen@cogen.UUCP (Alen Shapiro) writes:

>One of the topics touches on good C coding practices. I've hit a mental
>block about the reason ()s are used in preprocessor expressions like
>#define XXX (-1).
>
>--alen the Lisa slayer (it's a long story)

Here is a good general example of what can go wrong:

	% cat example.c
	#define RIGHT (4 + 4)	/* RIGHT must be 8 under any circumstances */
	#define WRONG 4 + 4	/* Will WRONG always equal 8? */

	main()
	{
		printf("%d\n", 3*RIGHT);	/* 3*8 = 24 */
		printf("%d\n", 3*WRONG);	/* Does it?? */
	}

	% cc -o example example.c
	% example
	24
	16

To understand what happenned, use the c preprocessor:

	% /lib/cpp example.c
	# 1 "example.c"



	main()
	{
		printf("%d\n", 3*(4 + 4));
		printf("%d\n", 3*4 + 4);	<- ahaaa!!
	}

dave@spool.wisc.edu (Dave Cohrs) (11/18/87)

In article <387@cogen.UUCP> alen@cogen.UUCP (Alen Shapiro) writes:
>I've hit a mental
>block about the reason ()s are used in preprocessor expressions like
>#define XXX (-1).

Consider this canned example:

#define NEGATE -1

main()
{
	int a;
	int b = 5;

	a=b NEGATE;
	printf("a should equal -5.  a = %d\n", a);
}

If NEGATE were a variable, this would generate a loud "syntax error".
But, because it's a #define, no error is generated, and the program
behaves strangely (the programmer meant to put a "*" between b and
NEGATE).

If you say

#define NEGATE (-1)

You get the "syntax error" you wanted expected.

Dave Cohrs
+1 608 262-6617                        UW-Madison Computer Sciences Department
dave@cs.wisc.edu                 ...!{harvard,ihnp4,rutgers,ucbvax}!uwvax!dave

ekrell@hector.UUCP (Eduardo Krell) (11/19/87)

In article <387@cogen.UUCP> alen@cogen.UUCP (Alen Shapiro) writes:

>#define XXX (-1)
>
>Please someone out in net-land, put me out of my mysery. Is there a potential
>confusion of unary minus with something else here?

what about an expression like "a-XXX" in your program? It will be converted
to "a--1" which doesn't look like legal C to me. On the other hand,
"a-(-1)" is OK.
    
    Eduardo Krell                   AT&T Bell Laboratories, Murray Hill

    {ihnp4,seismo,ucbvax}!ulysses!ekrell

ron@topaz.rutgers.edu (Ron Natalie) (11/19/87)

Why #define XXX	    (-1)


Consider
	i=XXX; ->	i=-1;

which should be the same even if it expanded, but nearly all compilers
support the "old fashioned assignment operator." or

	i = -XXX;  ->  i = --1;

which doesn't even compile.

Of couse nothing is foolproof...

	i = j XXX; would have been  j - 1
		not j(-1)

but people tend to use #defines interchangably with variables.

gwyn@brl-smoke.ARPA (Doug Gwyn ) (11/19/87)

In article <387@cogen.UUCP> alen@cogen.UUCP (Alen Shapiro) writes:
>block about the reason ()s are used in preprocessor expressions like
>#define XXX (-1).

-1 isn't much of a problem.  A better example is
	#define XXX (a + b)
for which
	XXX * c
has different meaning from what it would have were the parentheses
omitted.

For similar reasons, usually the arguments of a macro should be
wrapped with parentheses in the macro definition:
	#define ZZZ(i,j) ((i) * (j))
to prevent surprises with usages such as
	ZZZ(a+1,b+1)

If you don't see what the issue is, try expanding the above macro
invocations both with and without parentheses in the definitions,
then apply the C operator precedence/associativity rules.

chip@killer.UUCP (11/20/87)

In article <6700@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>For similar reasons, usually the arguments of a macro should be
>wrapped with parentheses in the macro definition:
>	#define ZZZ(i,j) ((i) * (j))
>to prevent surprises with usages such as
>	ZZZ(a+1,b+1)

I always assumed the golden rule "wrap macros in parens", until the following
bit me:

	#ifdef INTERN
	#   define EXTERN
	#   define INIT(X) =(X)
	#else
	#   define EXTERN extern
	#   define INIT(X)
	#endif

	EXTERN char message[] INIT("hello world");

This got me on our SVR2 Edge machine (with Greenhill C I think), which
didn't like parens around a string.  Can anybody say whether or not it
is reasonable to do this?

-- 
Chip Rosenthal, Dallas Semiconductor, (214) 450-0400, ...killer!vector!chip
This message courtesy of ``The UNIX Connection BBS'' in Dallas.
Neither they nor my employer are responsible for my stupidity.