Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!nbires!hao!boulder!sunybcs!rutgers!rochester!crowl From: crowl@cs.rochester.edu (Lawrence Crowl) Newsgroups: comp.lang.c Subject: Re: typeof isn't enough to define swap correctly Message-ID: <2105@sol.ARPA> Date: Thu, 10-Sep-87 22:54:23 EDT Article-I.D.: sol.2105 Posted: Thu Sep 10 22:54:23 1987 Date-Received: Sat, 12-Sep-87 15:49:13 EDT References: <557@rocky.STANFORD.EDU> <1880@sol.ARPA> <109@umigw.MIAMI.EDU> <2019@sfsup.UUCP> Reply-To: crowl@cs.rochester.edu (Lawrence Crowl) Organization: U of Rochester, CS Dept, Rochester, NY Lines: 64 In article <2019@sfsup.UUCP> mpl@sfsup.UUCP (M.P.Lindner) writes: >[Re: swap macros] Here's one that works WITHOUT TYPEOF AND WORKS FOR ARRAYS! > >#define swap(a, b) { \ > register int i; \ > for (i = 0; i < sizeof(a); i++) { \ > ((char *) &a)[i] ^= ((char *) &b)[i]; \ > ((char *) &b)[i] ^= ((char *) &a)[i]; \ > ((char *) &a)[i] ^= ((char *) &b)[i]; \ > } \ >} > >OK, so it's not as pretty or efficient as everyone would like, but it's >completely general purpose and doesn't need any new features. Well, it is not general purpose and does need new features. Here are the problems I see: 1. What if sizeof(a) != sizeof(b)? Correct calls will work, but should we accept incorrect calls? A simple check will fix this. 2. What if typeof(a) != typeof(b)? A simple check fixes this too if the typeof feature is added. 3. The above macro cannot be used in an expression. This seems irreparable without either calling a true function or extending C with a mechanism to declare variables within an expression (ala BCPL). 4. Most compilers complain about taking the address of an array. 5. Because you are taking the address, register variables cannot be arguments. 6. The call swap(i,j) will not work, because of the declaration of i. I assume you played xor games to avoid name clashes with the temporary. Unfortunately, you introduced one with the index variable. The only way I know to get around this is to play games with the preprocessor to construct identifiers. While this cannot be 100% effective, it is probably a practical solution. 7. Because the macro parameters are passed by name, if the arguments for a or b have side effects, the macro will not work. The only way to solve this problem is to evaluate each argument exactly once, which means you will have to take the arguments' addresses. (This brings back points 4 and 5.) 8. The loop is probably not the most efficient way to do this. Let's try again. I will ignore points 1 and 2 because they are easy. I will ignore points 3, 4 and 5 because they essentially cannot be fixed. I will try to address points 6, 7, and 8. /* the mechanism to construct new identifiers */ #define concat(n,m) n/**/m #define swap(a,b) { \ /* construct new type with new name */ typedef struct { char c[ sizeof(a) ] ; } concat(swap_T,__LINE__) ; \ /* pointers to sources allow evaluating arguments only once */ \ concat(swap_T,__LINE__) *concat(swap_P,__LINE__) = &(a) ; \ concat(swap_T,__LINE__) *concat(swap_Q,__LINE__) = &(b) ; \ /* do actual swap */ concat(swap_T,__LINE__) concat(swap_R,__LINE__) = *concat(swap_P,__LINE__) ; \ *concat(swap_P,__LINE__) = *concat(swap_Q,__LINE__) ; \ *concat(swap_Q,__LINE__) = concat(swap_R,__LINE__) ; \ } Have I forgotten anything? -- Lawrence Crowl 716-275-9499 University of Rochester crowl@cs.rochester.arpa Computer Science Department ...!{allegra,decvax,seismo}!rochester!crowl Rochester, New York, 14627