brnstnd@stealth.acf.nyu.edu (01/17/90)
Say swap() is defined as #define block do { #define endblock } while(0) #define swap(x,y,typ) block typ *_MV_x = x; typ *_MV_y = y; typ tmp;\ tmp = *_MV_x; *_MV_x = *_MV_y; *_MV_y = tmp; endblock Now constructions like swap(f++,g++,real) work and are faster than a function call. Most optimizers are even smart enough to realize that the do { } while(0) is purely syntactic. swap() does not work within an expression, and the macro will fail miserably if _MV_whatever is another macro. Other than that, does swap() have any side effects or other problems? Is anyone interested in a program that converts functions to these inline functions automatically? (Don't bother saying ``if typ is a struct or union and your compiler isn't ANSI then swap() will fail.'' I'm thinking about the problems of the conversion from function to macro, not of swap() in particular.) ---Dan
sullivan@aqdata.uucp (Michael T. Sullivan) (01/18/90)
From article <21068@stealth.acf.nyu.edu>, by brnstnd@stealth.acf.nyu.edu: > Say swap() is defined as > > #define block do { > #define endblock } while(0) > #define swap(x,y,typ) block typ *_MV_x = x; typ *_MV_y = y; typ tmp;\ > tmp = *_MV_x; *_MV_x = *_MV_y; *_MV_y = tmp; endblock Why are "block" and "endblock" even bothered with here. Why not just put the "do {" and "} while (0)" in the definition of swap? Could somebody please enlighten me. -- Michael Sullivan uunet!jarthur!aqdata!sullivan aQdata, Inc. sullivan@aqdata.uucp San Dimas, CA
eric@tqc.FIDONET.ORG (Eric Rouse) (01/18/90)
> Message-ID: <21068@stealth.acf.nyu.edu> > > Say swap() is defined as > > #define swap(x,y,typ) block typ *_MV_x = x; typ *_MV_y = y; typ tmp;\ > tmp = *_MV_x; *_MV_x = *_MV_y; *_MV_y = tmp; As long as your working with base types, or types you can cast to a base types like integers, longs etc, you might look into this one: #define Swap(X1,X2) { X1 ^= X2; X2 ^= X1; X1 ^= X2; } It's quite nice for integers, unsigned, longs, pointers etc. Plus it doesn't use any temp storage. Eric Rouse -- via The Q Continuum (FidoNet Node 1:382/31) UUCP: ...!rpp386!tqc!eric ARPA: eric@tqc.FIDONET.ORG
mikes@rtech.UUCP (Mike Schilling) (01/19/90)
From article <1990Jan18.002842.441@aqdata.uucp>, by sullivan@aqdata.uucp (Michael T. Sullivan): > From article <21068@stealth.acf.nyu.edu>, by brnstnd@stealth.acf.nyu.edu: >> Say swap() is defined as >> >> #define block do { >> #define endblock } while(0) >> #define swap(x,y,typ) block typ *_MV_x = x; typ *_MV_y = y; typ tmp;\ >> tmp = *_MV_x; *_MV_x = *_MV_y; *_MV_y = tmp; endblock > > Why are "block" and "endblock" even bothered with here. Why not just > put the "do {" and "} while (0)" in the definition of swap? Could > somebody please enlighten me. > -- In fact why use the do-while at all, and why use pointers? The classic swap macro is # define swap(x, y, typ) \ { \ typ tmp; \ \ tmp = y; y = x; x = tmp; \ } Is this just as good, or am I being *exceptionally* dense today?
john@stat.tamu.edu (John S. Price) (01/19/90)
In article <4514@rtech.rtech.com> mikes@rtech.UUCP (Mike Schilling) writes: >In fact why use the do-while at all, and why use pointers? The classic swap >macro is > ># define swap(x, y, typ) \ > { \ > typ tmp; \ > \ > tmp = y; y = x; x = tmp; \ > } > >Is this just as good, or am I being *exceptionally* dense today? The only problem I see with this, and it's not much of a problem, is that if you type swap(x,y,int); that will be expanded to { int tmp; tmp = y; y = x; x = tmp; }; with a semicolon at the end of the block, which isn't always wanted. The reason for the do { ... } while (0) is so that the semicolon can be put there without any problem. Most compilers just see the ; as a null statement and ignore it, anyway, but style wise it's not wanted. The do {...} while (0) loop is usually recognized by the compiler as a useless block, and optimized out, so that it doesn't do the comparison before it exits the block. It will see the 0 as always false, and optimize this out. -------------------------------------------------------------------------- John Price | Morals define our path through life, john@stat.tamu.edu | And everyone's path is different... - Me --------------------------------------------------------------------------
meissner@curley.osf.org (Michael Meissner) (01/19/90)
In article <4514@rtech.rtech.com> mikes@rtech.UUCP (Mike Schilling) writes: >In fact why use the do-while at all, and why use pointers? The classic swap >macro is > ># define swap(x, y, typ) \ > { \ > typ tmp; \ > \ > tmp = y; y = x; x = tmp; \ > } > >Is this just as good, or am I being *exceptionally* dense today? In terms of while the do/while(0), it is to support using the swap macro in an if statement. Consider the following fragment: if (condition) swap (a, b, int); else flag = TRUE; If the macro is defined as above, the ';' after the macro invocation will be treated as an empty statement, and the else will generate a compiler error. The do { ... } while (0) trick allows the ';' to properly end the statement. I originally wondered why the source to GNU C used this construct, until I realized about else statements. Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA Catproof is an oxymoron, Childproof is nearly so
rhg@cpsolv.CPS.COM (Richard H. Gumpertz) (01/19/90)
In article <21068@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: >Say swap() is defined as > >#define block do { >#define endblock } while(0) >#define swap(x,y,typ) block typ *_MV_x = x; typ *_MV_y = y; typ tmp;\ > tmp = *_MV_x; *_MV_x = *_MV_y; *_MV_y = tmp; endblock > >Now constructions like swap(f++,g++,real) work and are faster than a Stylistic nit: I would make it &(x) and &(y) in the first line of swap and make typ the first parameter and then make the call you show be swap(real, *f++, *g++) Maybe I am strange, but I find that easier to read. -- ========================================================================== | Richard H. Gumpertz rhg@CPS.COM (913) 642-1777 or (816) 891-3561 | | Computer Problem Solving, 8905 Mohawk Lane, Leawood, Kansas 66206-1749 | ==========================================================================
woody@rpp386.cactus.org (Woodrow Baker) (01/21/90)
In article <113.25B72444@tqc.FIDONET.ORG>, eric@tqc.FIDONET.ORG (Eric Rouse) writes: > > > #define Swap(X1,X2) { X1 ^= X2; X2 ^= X1; X1 ^= X2; } > > It's quite nice for integers, unsigned, longs, pointers etc. Plus it > doesn't use any temp storage. I use xor for maintaing pointers for linked lists. As the above line of code clearly shows, you can given a ^ b extract a or b if you know the other one. If you are traversing a linked list, you know either a or b (that is you know where you came from), so you can xor where you came from with the current node link and find out where you are going. It saves a pointer. Adding a node entry, you know where you are going to insert it, thus you know where you came from (the node just prior) and where the next node will reside, so you can use XOR to construct the pointer. Just a sidelight... Cheers Woody f > Eric Rouse -- via The Q Continuum (FidoNet Node 1:382/31) > UUCP: ...!rpp386!tqc!eric > ARPA: eric@tqc.FIDONET.ORG
bdm659@csc.anu.oz (01/22/90)
In article <17709@rpp386.cactus.org>, woody@rpp386.cactus.org (Woodrow Baker) writes: > In article <113.25B72444@tqc.FIDONET.ORG>, eric@tqc.FIDONET.ORG (Eric Rouse) writes: >> >> #define Swap(X1,X2) { X1 ^= X2; X2 ^= X1; X1 ^= X2; } >> >> It's quite nice for integers, unsigned, longs, pointers etc. Plus it >> doesn't use any temp storage. > I use xor for maintaing pointers for linked lists. As the above line of > code clearly shows, you can given a ^ b extract a or b if you know the > other one. If you are traversing a linked list, you know either a or b > ... The portability of this practice is not guaranteed by the ANSI C Standard. The arguments of ^ must have integral type, which doesn't include pointer types. You could try explicit casts, but there's no guarantee that any integral type is long enough to hold all the values of a pointer type and, even if there was, there is no guarantee that converting a pointer to an integral type and back to a pointer recovers the original value. The same goes for the Swap() macro above if X1 and X2 have pointer type. Brendan McKay. bdm@anucsd.oz.au or bdm659@csc1.anu.oz.au