Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!usc!brutus.cs.uiuc.edu!psuvax1!husc6!cmcl2!stealth.acf.nyu.edu!brnstnd From: brnstnd@stealth.acf.nyu.edu Newsgroups: comp.lang.c Subject: Summary: Is this swap() macro correct? Message-ID: <790@stealth.acf.nyu.edu> Date: 21 Jan 90 03:30:09 GMT References: <1990Jan18.002842.441@aqdata.uucp> <4514@rtech.rtech.com> Reply-To: brnstnd@stealth.acf.nyu.edu (Dan Bernstein) Distribution: usa Organization: IR Lines: 26 The macro is correct, except for namespace problems. I depend upon the user not doing anything like swap(x,_MV_x,real)---after all, the user isn't supposed to use such names. Then again, the macro shouldn't use them either! Without better namespace management there's no solution. do { ... } while(0) is the usual way to keep the macro working before an else. (Any language that doesn't terminate all its control structures should throw away its syntax and commit suicide, but that's a side issue.) Sorry for not explaining this. By the way, an empty do { } while(0) fails; define block as ``do { ;'' for general use. Several people asked what was wrong with #define swap(x,y,typ) { typ tmp; tmp = y; y = x; x = tmp; } There are two answers. The first is that this version has side effects. A macro foo(a,b,c) should reference each of a, b, and c exactly once. If the stdio macro writers understood this, putc(c,*f++) would work. The second is a more general religious argument: Macros should feel like functions. As above, they should reference each argument exactly once; if an argument is modified, the macro should use a pointer to it instead; and so on. The only exception is all-caps macros, which can do anything they want. I wouldn't mind seeing this convention more widely observed. ---Dan