ksbszabo@wateng.UUCP (Kevin Szabo) (01/21/85)
This bug affects users of Fred Fish's C Debugging Package. You may note that all of Fred's macros of the DBUG_X variety (x=1,2,3,4..) have the form: #define DBUG_2( keyword, format ) \ if(_db_on) {_dp_printf_( __LINE__, keyword, format );} In the very rare case of the following usage, the `else' clause will incorrectly bind to the `if(_db_on)' provided in the macro. if( some_thing_worth_noting_happens ) DBUG_2( "interesting", "info" ); else do the normal thing; Admittedly this program structure should really never occur, but it could surprise someone someday. The fix is to enclose the macro's in another set of {}. #define DBUG_2( keyword, format ) \ {if(_db_on) {_dp_printf_( __LINE__, keyword, format );};} I like many of the idea's in Fred's package and I will probably incorporate them into my own runtime macro's. One thing I would like to know is: Does anybody have a nice way of handling variable length argument lists to CPP? Since my variable names are usually meaningful I would like a macro that uses the variable names to create the format string. Thus I could do the following... int blood, sweat; float tears; ...... DBUG( LEVEL, "churchill", "%d,%d,%f", blood, sweat, tears ); Ideally the macro would change all this to if( debug & LEVEL ) { if( keyword("churchill) ) printf(" blood =%d, sweat= %d, tears= %f",....); (I use the bit vector LEVEL to select various areas of the package to be elegible for debugging). The only thing I have been able to come up with is the following HACK(!) DBUG( LEVEL, "keyword", "fmt", ( variable, argument, list )); #define DBUG( level, key, fmt, args ) {\ extern DebugLevel;\ if( DebugLevel & level ) {\ DebugStoreStrings( key, fmt,_LINE_, _FILE_,"args" );\ DebugPassValues args;\ }\ } Of course DebugPassValues() has to look at the format strings and use VARARGS stuff to decode its argument list. Does the extra set of parantheses used to fool CPP into thinking that there is only one set of arguments really gross anybody out? Is it portable at all? Especially the call to DebugPassValues, which requires CPP to retain the parantheses and thus create a valid function call? Kevin -- Kevin Szabo watmath!wateng!ksbszabo (U of Waterloo VLSI Group, Waterloo Ont.)
hugh@hcrvx1.UUCP (Hugh Redelmeier) (01/22/85)
In article <1885@wateng.UUCP> ksbszabo@wateng.UUCP (Kevin Szabo) writes: >You may note that all of Fred's macros ... >have the form: > >#define DBUG_2( keyword, format ) \ > if(_db_on) {_dp_printf_( __LINE__, keyword, format );} > >In the very rare case of the following usage, the `else' clause will >incorrectly bind to the `if(_db_on)' provided in the macro. > > if( some_thing_worth_noting_happens ) > DBUG_2( "interesting", "info" ); > else > do the normal thing; > >... The fix is to enclose the macro's in another >set of {}. > >#define DBUG_2( keyword, format ) \ > {if(_db_on) {_dp_printf_( __LINE__, keyword, format );};} > Whenever I define a macro to be an expression, I put parens around it to avoid surprises. Similarly, whenever I define a macro to be a (compound) statement, I put braces around it. There are two places where braces cause problems: IF statements with ELSE clauses and DO statements: void proc() { ... } #define mac() { ... } if (...) mac(); else ...; <---- wrong! if (...) mac() else ...; <---- right if (...) proc(); else ...; <---- right if (...) proc() else ...; <---- wrong! if (...) { proc_or_mac(); } while (...); <---- best? The same examples apply to DO. In fact, it applies even if the macro definition ends in semicolon, without the braces: #define mac() ...; I think this shows how the following three features of C don't combine perfectly: - semicolons as terminators (as opposed to separators) - semicolons DON'T terminate blocks - statement composition is not done with bracketing constructs (except for {}) PS: How often have you forgotten to put the semicolon after an initializer contained in braces? int primes[] = {2, 3, 5, 7, }; PPS: But thank goodness we can use the commas in an initializer as terminators (e.g. last comma above).