Access the contents of __VA_ARGS__ in a macro (not a function) - c

One can access the contents of ... inside a function using stdarg.h:
void fn(int nargs, ...){
va_list args; va_start(args,nargs);
i64 arg0 = va_arg(args,i64);
va_end(args);
}
The only way I know of using __VA_ARGS__ is to pass it to another macro or, eventually, a function. Eg.
#define __fn(...) fn(number_of_args(__VA_ARGS__), __VA_ARGS__)
but I wonder if it's possible to "unpack" the values of __VA_ARGS__ within a macro itself. Something like va_start(), va_arg(), and va_end(), but for macros.

if it's possible to "unpack" the values of VA_ARGS within a macro itself.
Yes, you can get the head #define HEAD(x, ...) x of the pack and iterate over the list with EVAL(EVAL(... recursive expansion. See https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms .
I find overloading on the number of macro arguments to produce way more readable error messages than EVAL(EVAL(.. expansions, so I prefer explicitly overloading for each argument.

Related

In C function declaration 'params, ...)' equal to 'params...)'?

all
In glusterfs's functions, there is one as follows
NOTES: the whole define in stack.h
//libglusterfs/src/glusterfs/stack.h
#define STACK_WIND(frame, rfn, obj, fn, params...) \
STACK_WIND_COMMON(frame, rfn, 0, NULL, obj, fn, params)
#define STACK_WIND_COMMON(frame, rfn, has_cookie, cky, obj, fn, params...) \
do { \
... \
next_xl_fn(_new, obj, params); \
THIS = old_THIS; \
} while (0)
I did not google search anything about explaining such declaring methods, any idea will be appreciated?
params... as part of function-like macro is a GNU extension before C standardized ellipsis as part of arguments of function-like macros.
See https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros
Nowadays, prefer __VA_ARGS__.
In C function declaration 'params, ...)' equal to 'params...)'?
No, they are not equal in function-like macros. The first one needs to use __VA_ARGS__ to reference variadic arguments and use __VA_OPT__ or ##__VA_ARGS__ to remove leading comma. In the params... then params is straight up replaced by all the arguments including commas.
Doing just ellipsis , ...) and using __VA_ARGS__ would be equal to , params...) and using params.
In normal functions params... as part of parameter-list is just invalid.

Variadic macro wrapper that expands to format string with characters corresponding to number of arguments

Question
I am looking for a variadic C preprocessor macro that passes its argument and a corresponding format string to a function, repeating a character depending on the number of arguments.
For example, I would like a macro FOO which expands as follows (or to equivalent C code):
FOO(1) → bar("d",1)
FOO(1,2) → bar("dd",1,2),
FOO(1,2,3) → bar("ddd",1,2,3)
bonus: FOO() → bar("")
While I can combine the solutions to C preprocessor macro for returning a string repeated a certain number of times and C++ preprocessor __VA_ARGS__ number of arguments (or similar questions) or use variadic macros, these have several drawbacks such as:
requiring special libraries, such as Boost (which would be an issue for me),
being compiler-dependent,
only working at runtime,
being extremely complicated.
My hope is that some better solutions emerge when these problems are not regarded separately.
Background
I want to callback Python functions in a C extension of Python in automatically generated code.
So, for example, I need foo(1,2,3) to expand to:
PyObject_CallObject( callback_foo, Py_Build_Value("(Oddd)",Y,1,2,3) )
I know that all arguments of foo are doubles, but I do not know their number.
(The above example is somewhat simplified. I am aware that it is missing a few Py_DECREFs.)
With 100% standard C, you could do this:
#define COUNT_ARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
#define STRTABLE (const char*[]){ "", "d", "dd", "ddd", "ddddd" } // and so on
#define FOO(...) bar(STRTABLE[COUNT_ARGS(__VA_ARGS__)], __VA_ARGS__)
In this example, STRTABLE is a compound literal look-up table with a bunch of string literals as an initializer list. Only the initializer corresponding to the number of arguments passed to the macro is used, by counting the number of macro arguments and using that array index specifically.
Full example:
#include <stdio.h>
#define COUNT_ARGS(...) (sizeof((int[]){__VA_ARGS__}) / sizeof(int))
#define STRTABLE (const char*[]){ "", "d", "dd", "ddd", "ddddd" } // and so on
#define FOO(...) bar(STRTABLE[COUNT_ARGS(__VA_ARGS__)], __VA_ARGS__)
void bar(const char* fmt, ...)
{
puts(fmt);
}
int main (void)
{
FOO(1);
FOO(1,2);
FOO(1,2,3);
}
The best I could come up with so far is to take this answer and simplify it:
# define EXPAND(x) x
# define FORMATSTRING(...) EXPAND(ELEVENTHARG1(__VA_ARGS__ __VA_OPT__(,) RSEQ()))
# define ELEVENTHARG1(...) EXPAND(ELEVENTHARG2(__VA_ARGS__))
# define ELEVENTHARG2(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
# define RSEQ() "dddddddddd","ddddddddd","dddddddd", \
"ddddddd","dddddd","ddddd","dddd","ddd","dd","d",""
# define FOO(...) bar( FORMATSTRING(__VA_ARGS__) __VA_OPT__(,) __VA_ARGS__ )
FOO() // expands to: bar( "" )
FOO(1) // expands to: bar( "d" , 1 )
FOO(1,2,3) // expands to: bar( "ddd" , 1,2,3 )
This works with GCC and Clang (with -std=c++2a) and up to ten arguments (but can be expanded).
The biggest compatibility issue are the two instances of __VA_OPT__(,), which are only required for handling the zero-argument case.
Otherwise, they can be replaced by a simple ,.
Just 2 macros:
#define GET_MACRO(_0,_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) bar(GET_MACRO(0,##__VA_ARGS__,"dddd","ddd","dd","d",""), ##__VA_ARGS__)

Macro with variable length of parameters

Is there a way to #define a macro with variable length of parameters?
#define CALL(ar1, ar2, ar3)
do something
#endif
in C code
CALL(0);
CALL(0,1);
CALL(0,1,2)
all invoke the above CALL macro. If ar2, ar3 not used, preprocessor just ignore the line with ar2 or ar3.
Yes, take a look at this one: http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
Key word is __VA_ARGS__ ( Variadic Macros ):
A macro can be declared to accept a variable number of arguments much as a function can. The syntax for defining the macro is similar to that of a function. Here is an example:
#define eprintf(...) fprintf (stderr, __VA_ARGS__)

Double slash comment substituition within a macro

I am developing a PIC MCU program on an ansi-compliant compiler (Microchip XC8).
There are two operation modes, determined via macros during compilation time.
So that I don't want to duplicate one function-like macro due to one line of code, I would like to know if there is any way to write a macro such as
#define FOO //
so that when FOO is substituted it will actually cancel the rest of the line.
Writing a function instead of a macro is out of the question because the delay generated by function calls would disrupt the tight timings of my program (around some microseconds).
You can't make a macro expand to comment out the line, no. // in a macro definition is a comment following the definition, it's not expanded, and IIRC there's a rule saying that you cannot construct a // using token-pasting. Even if you can, expanding it doesn't mean that the macro starts a comment. Basically, you don't get to change the comment syntax using macros.
You could do:
#if DO_NOTHING_MODE
#define FOO(ARG1)
#else
#define FOO(ARG1) ARG1
#endif
and use it like:
#define FUNCTION_LIKE_MACRO(ARG1, ARG2) \
required line; \
FOO(optional line;) \
Although a more common idiom is to design the macro to accept an expression as its argument, rather than a whole line:
#if DO_NOTHING_MODE
#define FOO(ARG1) ((void)0)
#else
#define FOO(ARG1) (ARG1)
#endif
and use it like FOO(optional line);
Either way, if the macro argument has commas in it, then the caller needs to enclose them in parentheses FOO((1,2)), although in C99 you can avoid that by making FOO a variadic macro:
#define FOO(...) (__VA_ARGS__)
You can use the #ifndef directive to achieve the same effect:
#ifndef FOO
your_line_of_code
#endif
EDIT: #SteveJessop made me see I didn't pay attention to this sentence of the OP "I don't want to duplicate one function-like macro due to one line of code". Here is what could be done in that case, if duplicating the function-like macro is not wanted:
// When FOO is defined, BLA in FUNC macro is a no-operation (null statement)
#ifndef FOO
#define BLA() a++
#else
#define BLA()
#endif
#define FUNC() \
BLA(); \
b++;
Comments are removed from the source before macro replacement occurs, so there's no way to define a macro exactly like that. However, it is certainly possible to pass an additional parameter into the macro to specify which code it should generate, or conditionally define the macro depending on the mode for which you are compiling.
#define FOO(...) __VA_ARGS__
And then use FOO(your code here) instead of FOO your code here in the macro.
If your platform doesn't have C99, you can instead use
#define FOO(x) x
and just make sure the argument doesn't contain a , not enclosed in ().

How to use __VA_ARGS__ inside a C function instead of macro? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
C/C++: Passing variable number of arguments around
I'm currently using the following macro declared on my C file.
#define COMMON_Print(...) printf (__VA_ARGS__)
Now that call works just fine, but turns out that I need to be able to create a C function that looks something like this:
void COMMON_Print(...)
{
printf (__VA_ARGS__);
}
So that function doesn't work, I get an error
"Error : undefined identifier __VA_ARGS__"
The complexity of my project requires to have a function since it's an interface... So how can I get the parameters ... and pass them to the printf function? Or better what am I doing wrong?
Thanks!
Each of the ?printf functions has a corresponding v?printf function which does the same thing but takes a va_list, a variable argument list.
#include <stdio.h>
#include <stdarg.h>
void COMMON_Print(char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
Side note: Notice that va_start takes the name of the last argument before the ... as a parameter. va_start is a macro which does some stack-based magic to retrieve the variable arguments and it needs the address of the last fixed argument to do this.
As a consequence of this, there has to be at least one fixed argument so you can pass it to va_start. This is why I added the format argument instead of sticking with the simpler COMMON_Print(...) declaration.
See: http://www.cplusplus.com/reference/clibrary/cstdio/vprintf/
__VA_ARGS__ is only for macros; variadic functions are rather different. You need to use va_start, va_arg and va_end from stdarg.h to handle them.
First, your function needs at least one named parameter, e.g.:
void COMMON_Print(const char* fmt, ...)
Then you can define a va_list and use va_start to set it:
va_list args;
va_start(args, fmt);
// your code here
va_end(args);
Now you can use args to access the arguments; calling va_arg(args, TYPE) will return the next variadic argument, so you can just keep calling that until you've read all the arguments.
If you're just trying to call printf, there's a printf variant called vprintf that takes the va_list directly:
vprintf(fmt, args);
There is no easy way to call one variadic function from another; you need something like vprintf that takes the whole va_list
__VA_ARGS__ is for macros only.
Chaining the variable number of argument to another function can't be done directly. Instead you have to
pass a va_list , and the function you're calling have to take a va_list. Luckily there's a variation of printf that does this, your function have to be written this way:
void COMMON_Print(char *format,...)
{
va_list args;
va_start(args,format);
vprintf(format,args);
va_end(args);
}
What you are looking for is the Ellipsis operator.

Resources