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

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.

Related

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

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.

c _Generic and macro funtion

I'm writing DEBUG_MSG for print debug messages
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
The _DEBUG_MSG_GENERIC is because I'd like to:
Show int message when a input parameter is int
Show char* message when a input parameter is char*
and its implement:
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
Now I'd like to implement _DEBUG_MSG_INT and _DEBUG_MSG_STR with Macro function and printf :
#define _DEBUG_MSG_INT(val) printf("%d\n", val);
#define _DEBUG_MSG_STR(str) printf("%s\n", str);
But I got error message is:
main.c:14:30: error: ‘_DEBUG_MSG_INT’ undeclared (first use in this function); did you mean ‘DEBUG_MSG’?
14 | int: _DEBUG_MSG_INT, \
| ^~~~~~~~~~~~~~
How do I solve it?
Does _generic only support function(pointer to function) and not support macro function?
Full Code
#include <stdio.h>
#define DEBUG_MSG(msg_str) _DEBUG_MSG_GENERIC(msg_str)
#define _DEBUG_MSG_GENERIC(strs) \
_Generic( (strs), \
int: _DEBUG_MSG_INT, \
default: _DEBUG_MSG_STR \
)(strs)
#define _DEBUG_MSG_INT(val) printf("%d\n", val)
#define _DEBUG_MSG_STR(str) printf("%s\n", str)
int main()
{
DEBUG_MSG("str");
DEBUG_MSG(5);
}
The problem is that both _DEBUG_MSG_INT and _DEBUG_MSG_STR are function-like macros thus they are only expanded if they are followed by ().
Note that macro expansion takes place before actual C compilation thus _Generic is nothing more than a common identifier at preprocessor stage.
I suggest using _Generic not for selection of the function pointer but rather for a formatting specifier to be used in printf(). Try:
#define _DEBUG_MSG_GENERIC(arg) printf( _DEBUG_MSG_FMTSPEC(arg), arg)
#define _DEBUG_MSG_FMTSPEC(arg) \
_Generic( (arg), int: "%d\n", default: "%s\n")
I believe your issue is because the preprocessor only makes one pass of the source code, so the printf's don't get substituted.
A quick solution would be to define _DEBUG_MSG_INT(val) and _DEBUG_MSG_STR(str) as real functions like so:
void _DEBUG_MSG_INT(int val) {
printf("%d\n", val);
}
void _DEBUG_MSG_STR(char * str) {
printf("%s\n", str);
}
The compiler will optimise out the extra function call overhead and will behave as if you called printf directly.
_Generic is not a preprocessor operation and cannot be used to select preprocessor macro functions. The code after a : in its cases must be a C expression (specifically an assignment-expression).
The code you have in those positions is _DEBUG_MSG_INT and _DEBUG_MSG_STR. Those are preprocessor macro names.
Those preprocessor macros are function-like macros. They are macro-replaced only when they are followed by a (. In your code, there is no ( after them, so they are not replaced.
That means the code after reprocessing looks like int : _DEBUG_MSG_INT,. So the compiler attempts to interpret _DEBUG_MSG_INT as an expression. Since _DEBUG_MSG_INT is not a declared identifier, the compiler reports an error that it is undeclared.
In summary, your code _Generic( (strs), int: _DEBUG_MSG_INT, default: _DEBUG_MSG_STR )(strs) attempts to use an after-preprocessing _Generic selection to select a preprocessing-time macro (either _DEBUG_MSG_INT or _DEBUG_MSG_STR) and then to have that macro treated as a function-like macros with the (strs) that appears after the _Generic. That simply cannot work; an after-preprocessing _Generic cannot select preprocessing macro names.

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 to call a function

I need a macro (or a function, but preferably a macro) that takes a function name and an unlimited number of arguments, then passes the arguments to the function. Let's say this macro is MACROFOO.
#define MACROFOO(function, ...) /* what do I put here?? */
int foo_bar(int x, int y)
{
// do stuff
}
int main(void)
{
int x = 3;
int y = 5;
MACROFOO(foo_bar, x, y); // calls foo_bar(x, y)
}
How could I define such a macro? I thought of doing something like:
#define MACROFOO(function, args...) (function)(args)
but it looks like that passes ... to the function, instead of the actual arguments. What should I do?
You can expand the ... of variadic macros with __VA_ARGS__.
Example:
#define MACROFOO(function, ...) (function)(__VA_ARGS__)
MACROFOO(printf, "hello world%c", '!')
/*^ expands to: (printf)("hello world%c", '!') */
Note: As you probably know, the parentheses prevent the function argument from being expanded as a macro (if it is a macro).
I.e.,
#define BAR(...) myprintf(__VA_ARGS__)
MACROFOO(BAR, "hello world%c", '!')
will expand to:
(BAR)("hello world%c", '!')
with the parentheses and
myprintf("hello world%c", '!')
if your remove them.
You can use either the standard variable argument __VA_ARGS__:
#define MACROFOO(function, ...) (function)(__VA_ARGS__)
or if you like a more descriptive name you can use this GNU CPP extension by writing a name immediately before ... :
#define MACROFOO(function, parameters...) (function)(parameters)
GNU CPP Section 3.6:
(...)
Variadic macros are a new feature in C99. GNU CPP has supported them
for a long time, but only with a named variable argument (‘args...’,
not ‘...’ and __VA_ARGS__).
If you are concerned with portability to
previous versions of GCC, you should use only named variable
arguments. On the other hand, if you are concerned with portability to
other conforming implementations of C99, you should use only
__VA_ARGS__.

what is ## in c?

I have seen this snippet:
#define kthread_create(threadfn, data, namefmt, arg...) \
kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
what does ## stand for ?
what is the meaning of ## when it appears out of a macro ?
Contrary to the other answers, this is actually GCC extension. When pasting variable args directly in, a problem occurs if no extra args were passed. Thus, GCC makes ## when used with __VA_ARGS__ or a varargs variable (declared with argname...). To paste if it contains a value, or remove the previous comma if not.
The documentation for this extension is here:
Second, the '##' token paste operator has a special meaning when placed between a comma and a variable argument. If you write
#define eprintf(format, ...) fprintf (stderr, format, ##__VA_ARGS__)
and the variable argument is left out when the eprintf macro is used, then the comma before the '##' will be deleted. This does not happen if you pass an empty argument, nor does it happen if the token preceding '##' is anything other than a comma.
eprintf ("success!\n")
==> fprintf(stderr, "success!\n");
The above explanation is ambiguous about the case where the only macro parameter is a variable arguments parameter, as it is meaningless to try to distinguish whether no argument at all is an empty argument or a missing argument. In this case the C99 standard is clear that the comma must remain, however the existing GCC extension used to swallow the comma. So CPP retains the comma when conforming to a specific C standard, and drops it otherwise.
This "pastes" whatever passed in arg to the macro expansion.
Example:
kthread_create(threadfn, data, namefmt, foo, bar, doo);
Expands to:
kthread_create_on_node(threadfn, data, -1, namefmt, foo, bar, doo);

Resources