Reputation: 3
I would like to create two macros. One of them will expand to function prototype and function content and the other one will expand to only function prototype. I'm thinking to create followings:
#ifdef SOME_CONDITION
#define MY_MACRO(prototype, content) prototype;
#else
#define MY_MACRO(prototype, content) prototype content
#endif
As an example usage
MY_MACRO(int foo(int a, int b)
,
{
return a + b;
}
)
These macros seems working fine. Do you think are those macros safe enough so that they will work for every kind of C code as intended? Or do you see any pitfall?
Upvotes: 0
Views: 150
Reputation: 2631
I actually did something similar quite recently and learned the pitfalls of passing in code as a macro argument.
For example try this seemingly correct code (using the first macro definition):
MY_MACRO(int foo(int a, int b)
,
{
int c = 1, d = 2;
return a + b + c + d;
}
)
You'll most likely see a compile error something to the tune of the macro expecting only 2 arguments while you provided 3.
What happens is that the macros are compiled by the pre-processor which doesn't care about C syntax. So in it's eyes, each ,
is a argument separator. So it thinks that the first argument to the macro is int foo(int a, int b)
, the second argument { int c = 1
and the third argument as d = 2; return a + b + c + d; }
.
So basically, the moral of the story is that "never pass in code as argument". Most macros that want to be flexible code-wise compile down into a if
or a for
statement (e.g. list_for_each
in http://lxr.free-electrons.com/source/include/linux/list.h#L407).
I'd suggest that you stick to standard #ifdef
ery in your situation. e.g.
#ifndef UNIT_TEST
int foo(...) {
//actual implementation
}
#else
int foo(..) {
return 0;
}
#endif
This sort of code is fairly standard: http://lxr.missinglinkelectronics.com/#linux+v3.13/include/linux/of.h (search for CONFIG_OF
)
Upvotes: 0
Reputation: 213940
Do you think are those macros safe enough so that they will work for every kind of C code as intended? Or do you see any pitfall?
Do not attempt to re-invent the C language. The people who read your code will be other C programmers. You can expect them to know C. You cannot expect them to know "the-home-brewed-garage-hacker-macro-language".
Strive to write code that is as simple as readable as possible. Avoid complexity, avoid confusion. Don't attempt to create solutions when there exists no problem to solve.
Upvotes: 1
Reputation: 78923
There are a lot of pitfalls, it is simply too naive, I think.
;
at the end. Nobody will be able to comprehend code like that that has function-like macros invocations in file scope without a terminating semicolon.,
operator, you are screwed.,
on the right hand side.This would work a bit better
#ifdef SOME_CONDITION
#define MY_MACRO(prototype, ...) prototype
#else
#define MY_MACRO(prototype, ...) prototype __VA_ARGS__ extern double dummyForMY_MACRO[]
#endif
you'd have to use that as
MY_MACRO(int foo(int a, int b), { return a + b; });
So this provides at least something visually more close to C code (well...) and handles the problem of the intermediate commas. The unused variable dummyForMY_MACRO
should cause no harm, but "eats" the ;
in the second form.
Not that I'd suggest that you use such a thing untested like this.
Upvotes: 2
Reputation: 199
Find below example which helps you to fulfils both of your requirements:
#ifdef SOME_CONDITION
#define MY_MACRO(a, b) \
int foo(int a, int b);
#else
#define MY_MACRO(a, b) \
int foo(int a, int b) \
{\
return 0;\
}
#endif
You can use 1st macro by MY_MACRO(a, b) and 2nd macro as MY_MACRO(a, b);
Upvotes: 0
Reputation: 74058
The first major pitfall, it doesn't work. When the second macro is used, it creates
int foo(int a, int b), { return a + b; }
which is not a valid function definition. To fix this, you must remove the ,
in the macro definition.
The second pitfall I see, usually C programmers don't use such fancy macros. It's simply confusing, when you're used to reading C source code.
If you're worried about diverging prototype declarations and corresponding function definitions, I suggest using appropriate compiler flags or tools. See this question and answers, How to find C functions without a prototype?
Upvotes: 4