Schauble@MIT-MULTICS.ARPA (Paul Schauble) (06/23/86)
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. 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.
bzs@bu-cs.UUCP (06/25/86)
The attached bit of total brain-damage seems to do the job in YAW (yet another way.) I don't actually proffer it as a solution that you might use, no way, don't bother...BUT Interesting question: What is the semantics of: sizeof(*ip++) ?? Try it before you guess, I was shocked (late entry for the obfuscated C contest??) The semantics I found are essential for my solution. P.S. It compiled and ran correctly on (code follows): Hardware OS Software Notes -------- --- -------- --------------- SUN3/180 UNIX4.2 R3.0 PCC DEC2060 TOPS-20 5.4 MIT/PCC provided bcopy() ATT/3B5 UNIX SYSVR2 C used memcpy() IBM3090/200 VPS/VM PCC provided bcopy() Encore/MultiMax UNIX 4.2 PCC VAX/750 UNIX 4.2 PCC VAX/780 VMS4.3 VMS/C provided bcopy() Celerity/1200 UNIX 4.2 PCC DG MV/10000 AOS/VS 6.03 MVUX 2.01/C used memcpy() I also tried it on the SUN, DEC2060, IBM3090, MV10000 and VAX750 with double's instead of ints and it compiled and worked fine, I don't have the energy right now to go through all the others, requests accepted. It also passes lint. YOW, am I portable yet? -Barry Shein, Boston University ____________ #include <stdio.h> #define swap(x,y) \ { \ char t1[sizeof(x)], t2[sizeof(t1)]; \ char *p, *q; \ \ p = (char *) &(x); \ q = (char *) &(y); \ bcopy(p,t1,sizeof(t1)); \ bcopy(q,t2,sizeof(t1)); \ bcopy(t2,p,sizeof(t1)); \ bcopy(t1,q,sizeof(t1)); \ } main(argc,argv) int argc; char **argv; { int ai[2], *ip = ai; int bi[2], *ip2 = bi; ai[0] = 1; ai[1] = 2; bi[0] = 3; bi[1] = 4; swap(*ip++,*ip2++); printf("ai[0] = %d *ip = %d bi[0] = %d *ip2 = %d\n", ai[0], *ip, bi[0], *ip2); exit(0); } Should print out something like: ai[0] = 3 *ip = 2 bi[0] = 1 *ip2 = 4 If I said I used memcpy() I added: #define bcopy(x,y,z) memcpy(y,x,z) If I said I provided bcopy() I added: bcopy(from,to,n) char *from, *to; int n; { while(n--) *to++ = *from++; }
sbanner1@uvicctr.UUCP (sbanner1) (06/25/86)
In article <1577@brl-smoke.ARPA> Schauble@MIT-MULTICS.ARPA (Paul Schauble) writes: >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. > >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. I don't think you were reading all of the replys too closely. While I can see the use of the 'typeof' operator [not macro], there is a relatively easy way to do this, as atleast one person mentioned : #define swap(type, a, b) {type temp ... } Granted this can get a bit ugly if you will need three or four types, or if they are complex, but the facility *IS* there. Disclamer : The veiws expressed here may not be shared my anyone else on the face of the earth. S. John Banner !uw-beaver!uvicctr!sbanner1 :UUCP ccsjb@uvvm :Bitnet
shap@bunker.UUCP (Joseph D. Shapiro) (06/26/86)
In article <1577@brl-smoke.ARPA> Schauble@MIT-MULTICS.ARPA (Paul Schauble) writes: >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. > ok, then, how about #define swap(x,y) \ { \ char * px = (char *)&(x); \ char * py = (char *)&(y); \ char t; \ int i; \ for (i=sizeof(x); i; i--) \ { \ t = *px; \ *px++ = *py; \ *py++ = t; \ } \ } Note that the sizeof(x) is a compiler constant and will not generate any code which might induce a side effect. Also, no flames about using char pointers, please, such use is guarenteed both in K&R and ANSI. Let me also say that I am neutral on the typeof() debate, I did this just for the challenge. For the doubtful, here is a working program. I have chosen x and y to be structs to remove any (most anyway) doubt. Program passes lint. ------ cut here ---- #define swap(x,y) \ { \ char * px = (char *)&(x); \ char * py = (char *)&(y); \ char t; \ int i; \ for (i=sizeof(x); i; i--) \ { \ t = *px; \ *px++ = *py; \ *py++ = t; \ } \ } #define peek(exp) printf("%s(%d): %s == %d\n",__FILE__,__LINE__,"exp",exp) struct sss { int i; long l; char c; } a,b, *pa, *pb; main() { a.i=1; a.l=2; a.c=3; b.i=11; b.l=22; b.c=33; peek(a.i); peek(a.l); peek(a.c); peek(b.i); peek(b.l); peek(b.c); pa= &a; pb= &b; peek(pa); peek(pb); swap( *pa++, *pb++ ); peek(pa); peek(pb); peek(a.i); peek(a.l); peek(a.c); peek(b.i); peek(b.l); peek(b.c); } -- -_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_ Joseph D. Shapiro "He who hesitates Bunker Ramo Information Systems is lunch" ...ittatc!bunker!shap ...decvax!bunker!shap
throopw@dg_rtp.UUCP (Wayne Throop) (06/27/86)
> Schauble@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
markb@sdcrdcf.UUCP (Mark Biggar) (06/27/86)
IT still doesn't work for REGISTER variables! Mark Biggar {allegra,burdvax,cbosgd,hplabs,ihnp4,akgua,sdcsvax}!sdcrdcf!markb
bzs@bu-cs.UUCP (Barry Shein) (06/28/86)
And then again, there's always this sort of thing (look in 4.2's
/usr/include/sys/mbuf.h for a strong precedent):
#define swap(x,y,t) { \
t *p1 = &(x), *p2 = &(y), tmp; \
\
tmp = *p1; \
*p1 = *p2; \
*p2 = tmp; \
}
which is called with something like:
swap(x,y,double);
really not a bad thing (or is it too much bother for the programmer to
know what type s/he is working with?) Still doesn't work with
registers of course (but I don't think typeof() would solve that
problem either.) Also, pointer types would have to be typedef'd to be
useful as swap(x,y,char *) would not quite work (but w/ a typedef
it works fine.)
-Barry Shein, Boston University
pete@valid.UUCP (Pete Zakel) (07/03/86)
> 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. What's wrong with the "swap(type, a, b)" invocation? You only need one macro declaration. Of course, you must declare the type each time you use it. -- -Pete Zakel (..!{hplabs,amd,pyramid,ihnp4}!pesnta!valid!pete)
pete@valid.UUCP (Pete Zakel) (07/04/86)
> IT still doesn't work for REGISTER variables! > > Mark Biggar Doesn't that depend on the C compiler? I've heard of compilers that ignore the "register" declaration if the address of the variable is taken. Of course I would HOPE that you would at least get a warning. -- -Pete Zakel (..!{hplabs,amd,pyramid,ihnp4}!pesnta!valid!pete)
mikeb@copper.UUCP (Mike Beckerman) (07/07/86)
I'm a little behind on my news for net.lang.c, but of the articles about the "SWAP" macro which I've read several have some form of copy involved. By copy I mean the use of "memcopy", or a cast to character and copy, etc. These may work in many cases, but they could be quite harmful when used on objects which have the "volatile" storage class. For example, if the objects were ints, and the swap is implemented as swapping 4 characters for each int, then each of the two ints would be accessed in some part 8 times (4 to read old 4 bytes, 4 to write new 4 bytes). Any comments? Mike
LINNDR%VUENGVAX.BITNET@WISCVM.ARPA (07/11/86)
In article <2498@mit-eddie.MIT.EDU> ambar@mit-eddie.ARPA (Jean Marie Diaz) writes: >In article <1321@psivax.UUCP> friesen@psivax.UUCP (Stanley Friesen) writes: >>In article <1946@brl-smoke.ARPA> gwyn@BRL.ARPA (VLD/VMB) writes: >>> >>> I haven't seen call-by-name included in any language since Algol. >> >> What about LISP? Or is LISP older than Algol? > >LISP and Pascal are both descendants of Algol 60. >-- This is a very curious assertion to make considering that LISP was also described in 1960. I would be interested in hearing why you think LISP is an ALGOL derivative. (we may be straying a bit from the topic of this newslist) David Linn ---------------------------------------------------------- ARPANET(?): LINNDR%VUENGVAX.BITNET@WISCVM.WISC.EDU BITNET: LINNDR@VUENGVAX.BITNET CSNET: drl@vanderbilt.csnet Ma Bell: (615)322-7924 USPS: P.O. 3241-B Vanderbilt Nashville, TN 37235 UUCP: ...psuvax1!vuengvax.bitnet!linndr
mouse@mcgill-vision.UUCP (07/12/86)
In article <857@bu-cs.UUCP>, bzs@bu-cs.UUCP (Barry Shein) writes: > And then again, there's always [...] > > #define swap(x,y,t) { \ > t *p1 = &(x), *p2 = &(y), tmp; \ > \ [...swap code...] > Also, pointer types would have to be typedef'd to be useful as > swap(x,y,char *) would not quite work (but w/ a typedef it works > fine.) Because you wrote the declaration carelessly. Should work fine if you write it as { \ t *p1 = &(x); t *p2 = &(y); t tmp; (assuming there are no side-effects in the type argument :-). See, now *I* always write declarations one declaration per variable, even writing int i; int j; instead of int i,j; This sort of thing is where the habit pays off (preen preen :-). Now you *still* need a typedef when the type involves arrays or functions (such as a pointer to function, a reasonable thing to want to exchange). I suspect there is no way around this, anyone care to produce a counterexample? -- der Mouse USA: {ihnp4,decvax,akgua,utzoo,etc}!utcsri!mcgill-vision!mouse philabs!micomvax!musocs!mcgill-vision!mouse Europe: mcvax!decvax!utcsri!mcgill-vision!mouse mcvax!seismo!cmcl2!philabs!micomvax!musocs!mcgill-vision!mouse ARPAnet: utcsri!mcgill-vision!mouse@uw-beaver.arpa "Come with me a few minutes, mortal, and we shall talk."