SWAP macro

Wayne Throop throopw at dg_rtp.UUCP
Fri Jun 27 07:53:12 AEST 1986


> Schauble at MIT-MULTICS.ARPA (Paul Schauble)
> I've gotten lots of respones to my request for a form of the macro that
> would make
>   swap(*a++, *b++);
>  work.  Almost all of them missed the point.  The swap requires a
> temporary.  Generating that temporary requires knowing the type.
> Several of the solutions would work fine if *a and *b were int's, but I
> never said that.

Yes, you did say that.  Your original posting gave the code fragment as:

>     int *a, *b;
>     swap (*a++,*b++);

This leads to the reasonable assumption that you were talking about the
case where a and b are integers.  Especially when the arguments you
mention have side effects, a notoriously difficult problem.

I think it completely justified that readers would assume you were
asking if there was any way to write a swap macro that works in the
presense of side effects.  In fact, I don't really see any other
plausible interpretation of the original posting.

> Recall the my original message was posted as a justification for a
> typeof macro, akin to sizeof.  I find that the need to generate
> temporaries in a macro is not uncommon.  Unless one is willing to do a
> different version of the macro for each type, you need a way to generate
> a new variable of the same type as one of the macro args.  The language
> provides no way to do this.

True, it does not.  But your original article did not mention "sizeof",
nor "typeof", nor propose any extensions to C.  Nor did it reference any
articles that did these things.  In any event, C *would* allow a macro
such as

        swap(a,b,int)
        swap(c,d,struct s *)

like so:

        #define swap(a,b,type) \
        {   type t;\
            t=a; a=b; b=t;\
        }

The trick to supress side effects can also be done, if needed.

        #define swap(a,b,type) \
        {   typedef type tdtype;\
            tdtype t, *pa = &(a), *pb = &(b);\
            t = *pa; *pa = *pb; *pb = t;\
        }
or
        #define swap(a,b,type) \
        {   type t; type *pa = &(a); type *pb = &(b);\
            t = *pa; *pa = *pb; *pb = t;\
        }

Note that these swap macros can only handle types that have no postfix
operators (that is, no [] or ()).  A typedef name must be supplied for
such cases.  Note also that the usual shortcomings of such macros apply.

Lastly, the stated problem can be solved fairly portably *without*
typeof.  That is, a fairly portable swap macro which works even for
arguments of unknown types, and works even in the presense of
side-effects is possible.  In vanilla C yet.

        #define swap(a,b) \
        {   char t[sizeof(a)], *pa = (char *)&(a), *pb = (char *)&(b);\
            memcpy(t,pa,sizeof(a)); memcpy(pa,pb,sizeof(a));\
            memcpy(pb,t,sizeof(a));\
        }

Limitations:
  - The usual problems with this macro being a bracketed construct at
        top level.
  - The usual name-hiding problems.
  - a and b must be the same type, and can't be register or bitfield.
  - It had better be legal on your machine to cast a pointer to any type
        you intend to swap to a pointer to character, and this cast must
        yield a manipulable character pointer.
  - Moving data of any type with character operations must yield valid
        data.
  - memcpy had better be builtin (or a macro) or this will run slower
        than ... well, pretty slow anyhow.

You wouldn't catch *me* using this macro, but it *does* solve the
stated problem, fairly portably, without resort to typeof.

--
"Typeof?  We don't need no steenkeen typeof!"
-- 
Wayne Throop      <the-known-world>!mcnc!rti-sel!dg_rtp!throopw



More information about the Comp.lang.c mailing list