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.