Ann O'Nymous <nob...@nowhere.com> writes: > On 7/28/2010 7:00 PM, pete wrote:
>> #define xyz(a,b,c,jkl) {\
> Thanks, but I can't actually do this. I simplified my problem, and am > actually using a variadic argument list.
Without the actual code (including the full range of calls that might be made) lots of answers may be wasted.
There is a big picture question that might help to have answered. Why not use a function? The answer may be that you can't re-write the two called functions to take a va_list, but that as least rules out the obvious solution.
>> Thanks, but I can't actually do this. I simplified my problem, and am >> actually using a variadic argument list.
> Without the actual code (including the full range of calls that might > be made) lots of answers may be wasted.
> There is a big picture question that might help to have answered. Why > not use a function? The answer may be that you can't re-write the two > called functions to take a va_list, but that as least rules out the > obvious solution.
OK. I simplified things so I'd get a generic answer so I'd know what to do next time. This is what I have at the moment:
void buildlist(unsigned int *,...); int zlink(int(int,...),int,unsigned int *);
#define LINKX(routine,flags,...)\ {unsigned int list[MAXARGS];\ buildlist(list,__VA_ARGS__);\ j = zlink((routine),(flags),list);\ }
"routine" is a function (one of many) called by zlink with a specialized parameter list in array list, and the functions cannot be changed. It returns int.
zlink() cannot be changed.
The "j=zlink()" is a hack to get the return value out.
Calls are like this:
int returnvalue1,returnvalue2; int j; int module1(int,...),module2(int,...); ... LINKX(module1,flag,1,2,3); returnvalue1=j; ... LINKX(module2,flag2,4,5,6,7,8,9); returnvalue2=j; ... I'd like to eliminate the "j=zlink() hack and change things so calls are like this:
> "routine" is a function (one of many) called by zlink with a specialized > parameter list in array list, and the functions cannot be changed. It > returns int.
> zlink() cannot be changed.
> The "j=zlink()" is a hack to get the return value out.
> Calls are like this:
> int returnvalue1,returnvalue2; > int j; > int module1(int,...),module2(int,...); > ... > LINKX(module1,flag,1,2,3); > returnvalue1=j; > ... > LINKX(module2,flag2,4,5,6,7,8,9); > returnvalue2=j; > ... > I'd like to eliminate the "j=zlink() hack and change things so calls are > like this:
> returnvalue1 = LINKX(module1,flag,1,2,3);
Why not put the return value as a LINKX argument before the valist? as in #define LINKX(routine, flags, returnvar,...)\ ... returnvar = zlink((routine),(falgs),list);
> expands equivalently to: [...] > jkl = function2(x,p,q,r); > On 7/28/2010 7:00 PM, pete wrote:
>> #define xyz(a,b,c,jkl) {\
> Thanks, but I can't actually do this. I simplified my problem, and am > actually using a variadic argument list.
Place the "return value" as the first parameter, rather than the last.
Now, this goes against many people's coding standards, as it hides the fact that it's going to change the value of that first parameter, but it does "work".
You could "unhide" this a little, by putting:
(*retval) = function2(x,p,q,r);
and passing:
xyz(&jkl,1,2,3);
It looks ugly, but again, it "works".
A minor(?) nit here is the "extraneous" semicolon in this syntax. Consider:
if ( foo ) xyz(&jkl,1,2,3); else xyz(&jkl,4,5,6);
This will expand to:
if ( foo ) { your macro }; else { your macro };
which will generate a syntax error. (Or, worse, not generate one if this is a nested if.)
I believe the "standard" way of handling this is to put the entire code block in a do...while(0) loop:
#define xyz(retval,x,y,z) do { \ ... your code ... \ } while (0)
Note the lack of a terminating semicolon on the while. This will be supplied by the semicolon in the "call" to the macro.
> "routine" is a function (one of many) called by zlink with a > specialized parameter list in array list, and the functions cannot be > changed. It returns int.
> zlink() cannot be changed.
> The "j=zlink()" is a hack to get the return value out.
> Calls are like this:
> int returnvalue1,returnvalue2; > int j; > int module1(int,...),module2(int,...); > ... > LINKX(module1,flag,1,2,3); > returnvalue1=j; > ... > LINKX(module2,flag2,4,5,6,7,8,9); > returnvalue2=j; > ... > I'd like to eliminate the "j=zlink() hack and change things so calls > are like this:
> returnvalue1 = LINKX(module1,flag,1,2,3);
What other bits of C99 can you use? If you can use compound literals you can turn the macro into a expression provided that you can change buildlist to return a pointer to its list:
> Why not put the return value as a LINKX argument before the valist? ... > This is what pete was suggesting I'd guess, why did you think it a bad > idea?
It's not a bad idea, and it's probably what I'll be doing. It just seems that there has to be a better way, a C function macro should be able to act like a function. I just want the code to look like a function call, since the called routines are often functions.
However, some of the time, they are not functions, or the function return value is ignored, meaning the extra parameter is not really used.
So, is there a way to rewrite LINKX to be able to use the syntax x=LINKX(module,flag,foo); or LINKX(module,flag,foo); ? If not, I'll add the extra parameter.
Also to Kenneth B, I am aware of the "do {...} while (0)" issue and may do that if I have calls like you mention. In fact, I'm sure I will have to do that. Also is "x = do {...} while (0);" valid C syntax? (if so, what does x get set to?)
Ann O'Nymous <nob...@nowhere.com> writes: > On 7/29/2010 1:40 PM, David Resnick wrote: >> Why not put the return value as a LINKX argument before the valist? > ... >> This is what pete was suggesting I'd guess, why did you think it a bad >> idea?
> It's not a bad idea, and it's probably what I'll be doing. It just > seems that there has to be a better way, a C function macro should be > able to act like a function. I just want the code to look like a > function call, since the called routines are often functions.
[...]
There is no such thing as a "function macro" or a "macro function" in C. There are "function-like macros", but those are merely macros with parameters.
Keep in mind that macro expansion is almost purely textual, and applies only to the macro invocation itself. For example, given:
x = MY_MACRO(y, z);
the expansion of MY_MACRO can't do anything with x.
-- Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst> Nokia "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"
On Jul 30, 11:39 am, Ann O'Nymous <nob...@nowhere.com> wrote:
> I'll probably do something like this, although I want to hide the > zlink_args stuff in the macro. Thanks.
Could you at all be interested in sharing a bit more about your requirement for building the arguments into an array that's all inside the macro?
For example, why use a macro at all? You could use a function that allocates the array, populates it from arguments, then calls 'zlink' and returns that call's result.
Also, consider a loop where we don't pass 'mylist':
enum { lim = 50 }; int i, rc, w, x, y, z;
w = x = y = z = 0; for (i = 0; i < lim; i++) { rc = LINKX(foo, (1 << 3) & (1 << 4), w, x, y, z); if (rc) { /* ... */ }
}
If you use Ben's suggestion of C99 compound literals within your 'LINKX' macro, you get nameless objects with automatic storage duration. When does their lifetime end? If it's the 'for' {} body, then what's to prevent allocating 50 of them above, as per 'lim'? That might get expensive.
Are you trying to make minimal changes to someone else's code? Are you using 'setjmp()' and friends and have concerns about allocating something like 'mylist' in a function's body? Or maybe you don't wish to add such an allocation to every function using the 'LINKX' macro?