markhall@pyrps5.pyramid.com (Mark Hall) (06/27/91)
In article <1991Jun24.213932.595@otago.ac.nz> andrew@otago.ac.nz writes: >I often get pissed off with the C pre-processor. Here is one thats been >getting up my wick for months. > >#define SWAP(a, b) {int c; c = a; a = b; b = c} Forgive me for this unsufferable horn-tooting; I just couldn't resist (I also couldn't believe no one else sent this reply :-). . . . NO macro will work for a swap. You suffer from the call-by-name rule which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]): int c; c = i; i = a[i]; a[i] = c; -Mark Hall (smart mailer): markhall@pyrps5.pyramid.com (uucp paths): {ames|decwrl|sun|seismo}!pyramid!markhall
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/27/91)
In article <160662@pyramid.pyramid.com>, markhall@pyrps5.pyramid.com (Mark Hall) writes: > Forgive me for this unsufferable horn-tooting; I just couldn't resist > (I also couldn't believe no one else sent this reply :-). . . . > NO macro will work for a swap. You suffer from the call-by-name rule > which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]): > > int c; c = i; i = a[i]; a[i] = c; Er, this turns out not to be the case. Consider #define swap(Type, This, That) \ do { \ Type *ThisQZ = &(This), *ThatQZ = &(That), t; \ t = *ThisQZ, *ThisQZ = *ThatQZ, *ThatQZ = t; \ } while (0) What happens to swap(int, i, a[i])? do { int *ThisQZ = &i, *ThatQZ = &a[i], t; t = *ThisQZ, *ThisQZ = *ThatQZ, *ThatQZ = t; } while (0); This is essentially what you'd get from inlining a call to a swap procedure with reference parameters. -- I agree with Jim Giles about many of the deficiencies of present UNIX.
grue@cs.uq.oz.au (Frobozz) (06/27/91)
In <160662@pyramid.pyramid.com> markhall@pyrps5.pyramid.com (Mark Hall) writes: >NO macro will work for a swap. You suffer from the call-by-name rule >which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]): > int c; c = i; i = a[i]; a[i] = c; Something like: #define SWAP(a, b) {int *ap = &a, *bp = &b, t; t = *ap; *ap = *bp; *bp = t; } removes the problems associated with the call by name (there are other problems present, but the call by name is gone). Each argument gets evaluated exactly once. There is no longer any call by name problems. This code will not work for register variables, but they do not suffer from the kind of problems above (if one parameter is a register variable, you can use it instead of it's pointer in the above and it will still work). Register variables are only an optimisation anyway, so they are not all that important --- I have a naive trust in modern compiliers to get the register allocation right. Pauli seeya Paul Dale | Internet/CSnet: grue@cs.uq.oz.au Dept of Computer Science| Bitnet: grue%cs.uq.oz.au@uunet.uu.net Uni of Qld | JANET: grue%cs.uq.oz.au@uk.ac.ukc Australia, 4072 | EAN: grue@cs.uq.oz | UUCP: uunet!munnari!cs.uq.oz!grue f4e6g4Qh4++ | JUNET: grue@cs.uq.oz.au --
kers@hplb.hpl.hp.com (Chris Dollin) (06/27/91)
Mark Hall writes:
NO macro will work for a swap. You suffer from the call-by-name rule
which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]):
int c; c = i; i = a[i]; a[i] = c;
Disclaimer: I am *not* advocating SWAP macros. But:
#define SWAP(x, y) \
{ int *splodge_x = &(x); int *splodge_y = &(y);
int splodge_t = *splodge_x; \
*splodge_x = *splodge_y; *splodge_y = splodge_t; }
does not suffer from the call-by-name problem (Algol 60 did not have
call-by-reference, but Algol 68 does (in a manner of speaking). Hence Mark's
criticism fails.
However, the amount of effort required to write even a specialised swap macro
should have suggested by now [anyone who hasn't, go read the FAQ] that swap
macros are dead ducks.
Dead, you hear me? D - E - D, DEAD.
We now return you to your regular sniping about the NULL pointer.
--
Regards, Chris ``GC's should take less than 0.1 second'' Dollin.
volpe@camelback.crd.ge.com (Christopher R Volpe) (06/28/91)
In article <160662@pyramid.pyramid.com>, markhall@pyrps5.pyramid.com (Mark Hall) writes: |>> |>>#define SWAP(a, b) {int c; c = a; a = b; b = c} |> |>Forgive me for this unsufferable horn-tooting; I just couldn't resist |>(I also couldn't believe no one else sent this reply :-). . . . |> |>NO macro will work for a swap. You suffer from the call-by-name rule |>which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]): |> |> int c; c = i; i = a[i]; a[i] = c; #define SWAP(a,b) {int c, *pa=&(a), *pb=&(b); c=*pa; *pa=*pb; *pb=c;} This doesn't solve all problems, but it gets the one you mentioned. I think. :-) ================== Chris Volpe G.E. Corporate R&D volpecr@crd.ge.com
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (06/28/91)
In article <6531@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > #define swap(Type, This, That) \ > do { \ > Type *ThisQZ = &(This), *ThatQZ = &(That), t; \ > t = *ThisQZ, *ThisQZ = *ThatQZ, *ThatQZ = t; \ > } while (0) You should call this SWAP. Without the uppercase, someone might be fooled into thinking that it works like a function. Namespace issues aside, there are three problems with this as a function: (1) You're using This and That by reference. (2) You're passing a Type argument. (3) This is a statement rather than an expression. SWAP(x,y,int) would be fine, though I don't think you lose anything by making the user indirect x and y: SWAP(&x,&y,int). ---Dan
mrm@nss1.com (Michael R. Miller) (06/28/91)
In article <160662@pyramid.pyramid.com>, markhall@pyrps5.pyramid.com (Mark Hall) writes: > ... > NO macro will work for a swap. You suffer from the call-by-name rule ^^^^^^^^ > which undid ALGOL in this case. Consider the expansion of SWAP(i,a[i]): > > int c; c = i; i = a[i]; a[i] = c; How about: #define swap(x, y) (x ^= y ^= x ^= y) Why won't this do the swap as requested? I've done this before. The only presumption, which was carried forward from the above text, is the types are compatible (not only size but type).
torek@elf.ee.lbl.gov (Chris Torek) (06/29/91)
In article <1991Jun28.134517.5972@nss1.com> mrm@nss1.com (Michael R. Miller) writes: >#define swap(x, y) (x ^= y ^= x ^= y) See the Frequently Asked Questions. This macro produces undefined results because it modifies an object more than once without an intervening sequence point. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/29/91)
In article <6531@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > In article <160662@pyramid.pyramid.com>, markhall@pyrps5.pyramid.com (Mark Hall) writes: >> NO macro will work for a swap. > Er, this turns out not to be the case. Consider > #define swap(Type, This, That) \ > do { \ > Type *ThisQZ = &(This), *ThatQZ = &(That), t; \ > t = *ThisQZ, *ThisQZ = *ThatQZ, *ThatQZ = t; \ > } while (0) That won't work because of the space following the third backslash. More seriously, that won't work if an argument doesn't have an address (eg, is a bitfield or a register variable) or one of the last two arguments happens to be called ThisQZ or ThatQZ. It also breaks if ThisQZ, ThatQZ, or t happens to be #defined to something other than a simple identifier. I'll stand with markhall on this one, at least until C gets gensyms and typeof. (Yes, I know gcc already has typeof. C doesn't.) der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/30/91)
In article <1991Jun29.125314.22043@thunder.mcrcim.mcgill.edu>, mouse@thunder.mcrcim.mcgill.edu (der Mouse) writes: > In article <6531@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > > In article <160662@pyramid.pyramid.com>, markhall@pyrps5.pyramid.com (Mark Hall) writes: > >> NO macro will work for a swap. > > > Er, this turns out not to be the case. Consider > > #define swap(Type, This, That) \ > > do { \ > > Type *ThisQZ = &(This), *ThatQZ = &(That), t; \ > > t = *ThisQZ, *ThisQZ = *ThatQZ, *ThatQZ = t; \ > > } while (0) > > More seriously, that won't work if an argument doesn't have an address That one I can't handle. The rest of the objections I can meet. static void swap(size_t size, char *a, char *b) { char t; while (size--) t = *a, *a = *b, *b = t; } #define swap(This, That) (swap)(sizeof (This), (char*)&(This), (char*)&(That)) (I know the function and the macro have the same name. I may have slipped up in the _way_ I did it, but ANSI C lets you do it.) -- I agree with Jim Giles about many of the deficiencies of present UNIX.