Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.lang Subject: Re: null statements Message-ID: <2565@umcp-cs.UUCP> Date: Wed, 23-Jul-86 06:02:29 EDT Article-I.D.: umcp-cs.2565 Posted: Wed Jul 23 06:02:29 1986 Date-Received: Thu, 24-Jul-86 01:31:11 EDT References: <800015@ccvaxa> <463@opus.nbires.UUCP> <442@sunybcs.UUCP> <484@valid.UUCP> Reply-To: chris@maryland.UUCP (Chris Torek) Organization: University of Maryland, Dept. of Computer Sci. Lines: 113 In article <484@valid.UUCP> sbs@valid.UUCP (Steven Brian McKechnie Sargent) writes: >Only a barbarian or Obfuscated C Contest winner would champion the use of > #define nothing /* do nothing */ >but I figured I'd mention it anyway. Actually, I came up with a use for something very like this recently. In C one can define a macro that `looks' like a function or procedure: /* successor function, mod 5 */ #define succ(i) (((i) + 1) % 5) In many cases the function is more complex: #define get_node() \ (freenodes ? \ (temp = freenodes, freenodes = freenodes->next, temp) : \ allocate_more_nodes()) If the macro is emulating a procedure, it need not even be an expression: #define proc(exp) \ if (exp) \ a(); \ else \ b() Note the lack of a semicolon. Instances of the macro include the semicolon, and it would not do to include it twice: v = e; proc(v); other(v); Sometimes, however, there is nothing to do in the `else' clause: #define SaveB(b) \ if ((b)->b_AfterGroupRst == NULL || \ (b)->b_AfterGroupRst->sv_level != CurrentGroup) \ DoSave(b); \ else \ /* do nothing */ This is fine in normal contexts: v = e; SaveB(v); other(v); However, now a missing semicolon can wreak silent havoc: v = e; SaveB(v) other(v); This expands to `if (v->b_...) DoSave(v); else other(v);'---not at all what was meant, but syntactically valid. One solution is to invert the `if': #define SaveB(b) \ if ((b)->b_AfterGroupRst != NULL && \ (b)->b_AfterGroupRst->sv_level == CurrentGroup) \ /* do nothing */ ; \ else \ DoSave(b) This is, however, confusing, at best. What is needed is an explicit `nothing'. In fact, this works: #define SaveB(b) \ if ((b)->b_AfterGroupRst == NULL || \ (b)->b_AfterGroupRst->sv_level != CurrentGroup) \ DoSave(b); \ else \ 0 since a constant is an expression, and an expression is a statement. This will make the case of the missing semicolon produce a syntax error. Unfortunately, it also makes `lint' complain (at least when used with `-h'). The solution below avoids both of these problems, but is hardly pretty: #ifdef lint #define do_nothing rand() #else #define do_nothing 0 #endif /* * Save a binding. */ #define SaveB(b) \ if ((b)->b_AfterGroupRst == NULL || \ (b)->b_AfterGroupRst->sv_level != CurrentGroup) \ DoSave(b); \ else \ do_nothing /* * Undo a save. */ #define UnSaveB(b) \ if ((b)->b_AfterGroupRst != NULL) \ DoUnsave(b); \ else \ do_nothing I think this also argues for an explicit `null statement'. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu