问题
I'm trying to change the behaviour of some functions in C with help of the preprocessor; and also add optional parameters that can be set on or off...
The basic pattern for the optional parameters is easy:
#ifdef OPT_PARAM
#define my_func(a, b, opt) _my_func(a, b, opt)
#else
#define my_func(a, b, opt) _my_func(a, b)
#endif
/*the rest of the code always calls "my_func" with all the params
and not the underscored version...*/
#ifdef OPT_PARAM
void _my_func(int a, int b, int opt)
#else
void _my_func(int a, int b)
#endif
{
/*... more #ifdefs surrounding opt uses */
}
the pattern for wrapping a function conditionally is similar, but the problem is that the underscores start to add up (one extra for each level of nesting, that can be a different function or just a #define for the next level in case it's not wrapped).
So, any ideas about how to reduce the code complexity here?
P.S. I'd be willing to use Python... but this is for a driver :-(
回答1:
Seems like you want to use default arguments or something that is not available in C. This seems to be a bad idea. Why not handle things in a more C fashion, where if you don't want to specify an argument you just pass NULL or -1 (standard).
void function (int a, int b, int c) {
if (c != -1) {
// something
}
}
function(a,b,-1);
function(a,b,c);
回答2:
Can you use a C++ compiler? You could use (of C++ features) just function overloading.
Another option is
#ifdef OPT_PARAM
# define OPT(X) , X
#else
# define OPT(X)
#endif
int my_func(int a, int b OPT(int opt) ) {
#ifndef OPT_PARAM
int opt = default_value;
#endif
... // Rest of code
}
...
// calling it
my_func(2, 4 OPT( 42 ) );
回答3:
I think this may be closer to what you want, but I am unsure. My understanding is the idea is to allow c functions with arbitrary numbers of arguments, that are type checked and can be eliminated at compile time.
Let me warn you about the use of underscores in identifiers, by quoting the standard. You may run into a reserved identifier. However, the likelihood of this is unknown to me.
ISO/IEC 9899:1999 (E) 7.1.3
— All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
This solution requires GCC. The version of GCC must also support weak symbols. The idea is to allow the compiler to look for the right function definition using weak symbols. Additionally the contents of the function are simplified by using the knowledge that the compiler should prune dead branches, ie:
if (0) { ... }
at compile time without further analysis (GCC 4.x certainly does this). By defining the non-existent optional parameters as c pre-processor (cpp) symbolsyou can avoid having cpp conditionals in the function body (if so desired). See how opt1 and opt2 are defined for f_opt0 below.
#include <assert.h>
#include <stdio.h>
extern void f_opt0(int a, int b) __attribute__((weak));
extern void f_opt1(int a, int b, int opt1) __attribute__((weak));
extern void f_opt2(int a, int b, int opt1, int opt2) __attribute__((weak));
#ifdef OPT0
void f_opt0(int a, int b) {
#define opt1 0
#define opt2 0
#endif
#ifdef OPT1
void f_opt1(int a, int b, int opt1) {
#define opt2 0
#endif
#ifdef OPT2
void f_opt2(int a, int b, int opt1, int opt2) {
#endif
if (opt1) printf("opt1=%d\n", opt1);
if (opt2) printf("opt2=%d\n", opt2);
printf("a+b=%d\n", a+b);
#undef opt1
#undef opt2
}
#define f(a, b, o1, o2) \
if (f_opt2) f_opt2(a, b, o1, o2); \
else if (f_opt1) f_opt1(a, b, o1); \
else if (f_opt0) f_opt0(a, b); \
else { assert(0 && "no f() defined!"); }
int main(void) {
f(1, 2, 1, 1);
return 0;
}
My testing was very limited, and I do not advocate this as good design in C. It seems prone to problems and is troublesome to comprehend. However, I hope it addresses your goals.
回答4:
In the end I just added a new decorator that handled uniformly the extra parameters and changed the obscure underscores by more descriptive names.
Now it's a more orthogonal design in which I can plug and unplug behaviour at compile time with no runtime overhead.
来源:https://stackoverflow.com/questions/1178530/c-function-decorators-wrappers-at-compile-time