Problems with variable macros in C

I have a problem with optional arguments in # define statements in C , specifically in gcc 4.2:

bool func1(bool tmp) { return false; } void func2(bool tmp, bool tmp2) {} #define CALL(func, tmp, ...) func(tmp, ##__VA_ARGS__) int main() { // this compiles CALL(func2, CALL(func1, false), false); // this fails with: Implicit declaration of function 'CALL' CALL(func2, false, CALL(func1, false)); } 

This is clearly a contrived example, but shows a problem. Does anyone know how I can get the optional arguments β€œcorrectly”?


Additional info: If I remove ## to __VA_ARGS__ and do something like this:

 bool func2(bool tmp, bool tmp2) { return false; } #define CALL(func, tmp, ...) func(tmp, __VA_ARGS__) int main() { CALL(func2, false, CALL(func2, false, false)); } 

This compiles, but it no longer works with null arguments since it allows func(tmp, )

EDIT : right after converting all my code to rely on P99 instead of what I had before (which ultimately upset my code), I accidentally discovered that this works:

 bool func1(bool tmp) { return false; } void func2(bool tmp, bool tmp2) {} #define CALL2(func, tmp, p...) func(tmp, ##p) #define CALL(func, tmp...) CALL2(func, tmp) int main() { // works CALL(func2, CALL(func1, false), false); // ...also works CALL(func2, false, CALL(func1, false)); } 

Compiles and works with any number of parameters (and the correct values ​​are passed and returned), but ... should this be legal?

+4
source share
3 answers

The ## operator performs exact token substitution, so in this case it tries to send the token "CALL(func1, false)" as the last argument to the func1 C function.

The problem is that CALL is a macro, and you cannot insert macro variables into the list ##__VA_ARGS__ .

The reason it works when an internal macro is passed as a named argument is because the preprocessor will parse the named arguments for the internal macros, but not ##__VA_ARGS__ , where there is a simple token replacement.

One way to solve this problem is to assign the result of the internal CALL variable to the placeholder variable, and then pass it along with the macro.

 int main() { CALL(func2, CALL(func1, false), false); bool result = CALL(func1, false); CALL(func2, false, result); } 

Another way to solve this problem is to simply use __VA_ARGS__ as the only argument to the func function, and this will allow you to pass nested macros, for example:

 #define CALL(func, ...) func(__VA_ARGS__) int main() { CALL(func2, false, CALL(func2, false, false)); } 

Analyze your dilemma in more detail:

 CALL(func2, false, CALL(func1, false)) 

In this particular macro call, CALL now ("func2", "tmp", CALL(func1, false)) so he tries to call func1 , passing in tmp and, well, CALL(func1, false) .

Here the line is output between the preprocessor and the actual C compiler.

The preprocessor, after it starts performing the substitution, performed the parsing, so the compiler gets CALL(func1, false) as the actual C function, not a macro, because the compiler does not know about macros, but only the preprocessor.

+14
source

You are using the gcc extension with the construction , ## . This is probably not recommended if you have mobility.

With a little effort, you can create macros that can respond to the number of arguments they receive and make the correct replacement. P99 provides helpers for this:

 #define CALL(...) P99_IF_EQ_2(P99_NARG(__VA_ARGS__))(dosomethingwithtwo(__VA_ARGS__))(dosomethingwithmore(__VA_ARGS__)) 

But in your case, I think there is a simple solution:

 #define CALL(func, ...) func(__VA_ARGS__) 
+4
source

So, I just converted my code to use the design mentioned at the end of my initial post and it started working again again. I am going to assume that there was a typo with my P99 packaging.

Now it compiles and functions correctly for any number of arguments and any number of nesting, like any parameter. Thanks everyone!

0
source

Source: https://habr.com/ru/post/1333937/


All Articles