I bumped into the following macro while analyzing a code.
#define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra)
The function name is passed as an argument to __COMMAND_HANDLER however there is no definition of this function anywhere else in the code. The cmd argument's type (command_invocation) is defined. Basically I couldn't understand the functionality of this macro because I couldn't find the definition of the function name. Is name some kind of pre-defined function in standard C library ? Does this macro definition make sense if name is not defined ?
Durning preprocession, the preprocessor will replace all occurrences of __COMMAND_HANDLER(name, extra ...) macro to its body with replacing each occurences of name and extra... inside its body to the tokens you specified.
This means in this case that whatever you enter for name argument, it will be a function name, and extra... will be its additional parameters beside the first one (struct command_invocation *cmd).
For example the following line:
__COMMAND_HANDLER(foo, int param) {
/* definition */
}
after preprocessing will be:
int foo(struct command_invocation *cmd, int param) {
/* definition */
}
One important thing has to be clarified: the ## before extra and named variable argument (using extra... instead of ...) are not the part of the c standard but they are GNU extensions. The effect of ## after comma lets you specify nothing for variable argument. Compiling your example with GCC (with -pedantic flag) when it's used as follows, you will see warning messages:
/* The following example will print the following messages:
* warning: ISO C does not permit named variadic macros [-Wvariadic-macros]
* warning: ISO C99 requires at least one argument for the "..." in a variadic
* macro
*/
__COMMAND_HANDLER(bar);
Normally the ## is the operator for token concatenation, i.e. two tokens on either side of a ## operator are combined into a single one. For example:
#include <stdio.h>
#define FOO(name, number) void name##number()
FOO(bar, 1) { puts("I'm first."); }
FOO(bar, 2) { puts("I'm second."); }
int main() {
bar1();
bar2();
return 0;
}
This is a macro and name is a parameter.
You use it like this:
__COMMAND_HANDLER(hello, char* world)
During pre-process stage, it would transform your code into:
int hello(struct command_invocation *cmd, char *world);
In this case, name is passed as hello, and extra = char* world.
If you don't pass anything for extra, ## will discard the comma.
In short: the macro is creating the function with the name specified by the parameter name and optional additional arguments specified by extra ....
Note: names starting with a double underscore is implementation reserved and shouldn't be used.
The macro is variadic.
The second argument to the macro extra ... provides a name to use instead of the default __VA_ARGS__ inside the function declaration macro. This is a GNU extension
## extra is another GNU extension that specifies to the preprocessor that if the second argument to the macro __COMMAND_HANDLER is omitted, the preceding comma can be removed and the function called without it.
The reason you can't find the declaration of name is because it's a parameter to your macro! The macro itself is declaring a new function with whatever is in name, and the arguments provided, with the default first argument of struct command_invocation *cmd.
Here are some examples:
Calling:
__COMMAND_HANDLER(cmd,char * w)
Would result in the function declaration of:
int cmd(struct command_invocation *cmd,char * w)
Whereas calling:
__COMMAND_HANDLER(cmd2)
would result in the function declaration of:
int cmd2(struct command_invocation *cmd)
Related
I'm trying to use systemd's helper macros, but I don't quite understand the working mechanism. Systemd macros as below;
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
*p = func(*p); \
}
I did not understand how to give the "p" parameter as an argument in the macro I mentioned above. I would like to explain the problem with an example.
First of all, I created udev enumerate object;
struct udev_enumerate* enumerate = udev_enumerate_new(pudev);
When I want to delete this object later, how do I do it using the systemd macro?
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate*, udev_enumerate_unref);
Type and function are specified according to the macro, but how is the "p" parameter in the macro (ie the object that I produced) specified in the macro?
"p" is not a parameter. It's just a text "p". I guess it is intended to stay for word "pointer". I found the mentioned line at link. It looks that the macro is used to create a wrapper for a given cleanup functions that checks if the given pointer is not NULL and set the pointer to a cleaned object to the empty sentinel. I can guess that the trailing "p" is the naming convention used in this project. After a few cleanup functions created with this macro there are some others like freep() and unmaskp().
For example DEFINE_TRIVIAL_CLEANUP_FUNC(int, myclean) expands as:
static inline void mycleanp(int *p) {
if (*p)
*p = myclean(*p);
}
Assuming that the udev_enumerate_unref() is declared as:
struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
the wrapped can be created with:
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_enumerate *, udev_enumerate_unref)
And used as:
struct udev_enumerate* enumerate = udev_enumerate_new(pudev);
... do stuff with `enumerate`
udev_enumerate_unrefp(&enumerate);
I have a problem. The concept of Object Oriented Programming in C got homework. I need to use variadic functions. But I get a mistake. I'd appreciate it if you could help me. I'm new to encoding.
RastgeleKarakter.h :
#ifndef RASTGELEKARAKTER_H
#define RASTGELEKARAKTER_H
struct RASTGELEKARAKTER{
// code
};
RastgeleKarakter SKarakterOlustur(int...); // prototype
void Print(const RastgeleKarakter);
#endif
RastgeleKarakter.c :
#include "RastgeleKarakter.h"
#include "stdarg.h
RastgeleKarakter SKarakterOlustur(int... characters){
//code
}
Error :
make
gcc -I ./include/ -o ./lib/test.o -c ./src/Test.c
In file included from ./src/Test.c:3:0:
./include/RastgeleKarakter.h:17:38: error: expected ';', ',' or ')' before '...' token
RastgeleKarakter SKarakterOlustur(int...);
I don't know how many parameters there are. I want to solve this with the variable function.
The parameter list should not have a type nor a name
RastgeleKarakter SKarakterOlustur(int count, ...)
{
va_list args;
va_start(args, count);
int i = va_arg(args, int);
}
Use the macros defined in stdarg.h header file to access the parameter list. further reading
If by your original deceleration, you meant that all members of the parameter list are integers, and since you will be supplying the count anyway, consider changing it to int count, int * list
Variadic arguments in C are untyped and unnamed. The correct prototype for a variadic function is:
returnType functionName(type1 ordinaryArg1, type2 ordinaryArg2, ...)
You need at least one ordinary arguments before the .... You can only access the variadic arguments through the functions from stdarg.h.
The error says that the compiler expects one of the following before the ellipsis:
-semicolon
-comma
-closing parentheses
So, the prototype is not declared correctly.
The declaration needs at least one named variable and the last parameter must be the ellipsis.
For example, if you intend to pass integers to the method, the declaration could be as follows:
int sum (int count, ...);
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__.
I have the following lines of code, created by a database export program:
typedef struct _s8_VARB
{
unsigned char _byte[8];
} s8_VARB;
const s8_VARB varb00[] = {
mMM(1,25,22,12,0,0,0,0,27)
mMM(0,1,29,12,0,0,0,0,21)
mMM(1,1,36,12,0,0,0,0,22)
}
The mMM is a macro that I want to define with a functionality that will produce the following data during compilation:
const s8_VARB varb00[] = {
1,25,22,12,0,0,0,0,27,
1,1,36,12,0,0,0,0,22,
}
So it basically should check the 1st parameter. If it is 0, that complete line should omitted. If it is 1, all the parameters (except the 1st) should be 'put on the line', ending with a comma.
What I have tried is this:
#define COMMA ,
#define mMM(cond, a,b,c,d,e,f,g,h) (cond) ? (a),(b),(c),(d),(e),(f),(g),(h) COMMA :
But this is not working. Not even compiling, as gcc complains:
error: expected expression before ':' token
How should this macro definition should look like? Is this possible at all in C?
You can initialize an array with constant data only. A conditional statement is by definition not constant (even if it's known to the compiler at compile time).
Instead you could do it like this:
#define _mMM0(...)
#define _mMM1(...) {__VA_ARGS__},
#define mMM(cond, ...) _mMM##cond(__VA_ARGS__)
const unsigned char varb00[][8] = {
mMM(1,25,22,12,0,0,0,0,27)
mMM(0,1,29,12,0,0,0,0,21)
mMM(1,1,36,12,0,0,0,0,22)
};
I removed the struct and replaced it with its only member directly. In case C99 is not available, you can name every parameter as you used to do.
Here's a hackish solution. If the number of arguments is fixed and you can't use C99+, then you could list them explicitly instead of using ... and __VA_ARGS__.
#define mMM(x, ...) mMM##x(__VA_ARGS__)
#define mMM0(...)
#define mMM1(...) __VA_ARGS__,
The ## operator pastes the token mMM and the x argument together to form a new macro name -- either mMM0 or mMM1 -- which is then called with the remaining arguments. mMM0() in turn expands to nothing, and mMM1() expands to its arguments.
(The extra trailing comma after the last element won't be a problem by the way. int a[] = { 1, 2, 3, } is explicitly allowed syntax in C.)
As a side note, invoking a macro like
#define m(x) (x) ? 1 : 2
using e.g. m(0) will simply expand it to (0) ? 1 : 2. The ternary operator will not be handled in the preprocessor.
what is "__printflike__ modifier" exactly? what does this term mean?
At a guess it tells the compiler you're using that a function takes arguments in the form [anything, ] format, ... where the format, ... part look like the arguments to printf. The __printflike__ attribute lets the compiler test the types in the argument list against the string format. This comes up when you write a function like log(format, ...) and use vsprintf to subordinate the formatting work to the usual standard library functions before sending the string to some special log interface.
If you are using GCC then it is probably a #define in your project something like:
#define __printflike__ __attribute__((format(printf, 1, 2)))
Where 1, 2 means that format, ... appear in positions 1 and 2.
I have a function in my error reporting library with the declaration in the header like:
extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...)
PRINTFLIKE(4,5);
The PRINTFLIKE is in upper-case so that I can define it as nothing when I'm not using GCC. This use says that the first three arguments are nothing special, but the fourth argument is a format string like the ones used by printf() (indeed, internally, it gets passed to vfprintf()), and the arguments corresponding to it (formatted using the format string) start with the fifth argument.
This means that if I type:
err_logmsg(stdout, ERR_ABORT, 1, "%s: %d\n", errno, strerror(errno));
I will get a compilation error because errno is an int and strerror(errno) returns a pointer to a string. I can fix the error by changing the format string or the fifth and sixth arguments. (ERR_ABORT is a set of flags defined in the same header that declares err_logmsg().)
There are two numbers in the PRINTFLIKE macro because there could be other arguments between the format string and the first of the arguments used by the format string. For example, an alternative function could be:
extern void err_writer(FILE *fp, const char *format, int flags, int estat, ...)
PRINTFLIKE(2,5);
This tells the compiler that the format string is the second argument, but that the corresponding arguments that get formatted still appear starting at the fifth argument.
The header file for this code contains the lines:
#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN() __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN() /* If only */
#endif /* __GNUC__ */
Probably tells the compiler that the corresponding function has printf-like semantics.
This can enable the compiler to issue warnings at compile-time when the modifiers in the format string do not correspond to the type or the count of the passed arguments.
There is no other way that the compiler can have the knowledge to tell you that %u isn't the right formatting for an int when calling printf, sprintf, fprintf, etc.
I asked the reverse question a few months ago: Are printf/sprintf compiler warnings a conceptual break?