C Macro for defining test methods with callbacks - c

So you can dynamically define a method with its own name like this:
#define test(name) void name() { print("#name"); }
Then you can call it like:
test(foo);
foo();
I'm wondering though if you can make a "callback"-style form, like this:
#define test(name, body) void name() { print(#name); body(); }
Where it invokes a body that is defined as sort of a "block" like this:
test(dosomething, {
int a = add(1, 1);
assert(a == 2);
})
But more than that, I would like to pass a callback for async functions to say they are complete, like this:
test(dosomething, { (done)
int a = add(1, 1);
assert(a == 2);
done();
})
In addition, I am defining these outside of the main, so it would be defined in the same scope as a normal function. Because of that, the tests aren't going to automatically run. They need to be iterated over. As such, they probably need to be pushed into an array of some sort. So wondering how that could be done, if macros allow you to sort of capture stuff into an array, or to build up an enum one #define at a time.
#define test(name, body) void name() { \
print(#name); \
} \
\
TESTS[CURRENT_TEST++] = &name \ // push the test into a TESTS array.
So then in main you can iterate over them:
int
main() {
iterate over TESTS...
}
To summarize, I am wondering how to #define this at the file body level (i.e. not in main, but at the level of functions):
void afunction() { printf("Foo"); }
test(dosomething, { (done)
int a = add(1, 1);
assert(a == 2);
done();
})
void anotherfunction() { printf("Bar"); }
such that I can iterate over the tests in main.
This suggests blocks are possible in macros.

Looks like you're building some sort of mini test framework using the c preprocessor.
There's a caveat for the bodies; to the C preprocessor, curly brackets and square brackets are just tokens. Parenthesized expressions are recognized (i.e., parentheses are matched), and commas are recognized as delimiters. So for example, this macro invocation:
test(dosomething, { int a = add(1, 1); assert(a == 2); })
...has two arguments despite having two commas (because the second comma is "hugged" in a parenthesized set), but that's a bit misleading. This invocation:
test(dosomething, { enum { red, green, blue }; assert(red+1==green); })
...has four arguments: 1: dosomething, 2: { enum { red, 3: green, and 4: blue }; assert(red+1==green); }. If you're going to do this, you probably want to cover cases like this... there are basic strategies: (a) hug the body in parentheses (you can unwrap it in expansion), or (b) use variadic macros.
They need to be iterated over.
Sounds like a job for x-macros (below I'll be using the parameterized-macro flavor of x-macros).
But more than that, I would like to pass a callback for async functions to say they are complete, like this:
...you can't add an argument in the middle, but the braces don't have to be part of this (they don't help anyway, since the preprocessor ignores them). So for the above, we probably want to pick the hug option. That leaves your invocations looking like this:
test(dosomething, (int a=add(1,1); assert(a==2);), done)
However, since we're ripping the curly braces out, we can put them in arbitrary places in our expansion and do arbitrary things in between. Since I'm guessing you want the same kind of async thing going on, we could just put that thing in the expansion that generates the definition rather as an argument.
Here's roughly what it would look like, using a parameterized macro version of x-macros, and applying an async on expansion (using semaphores to demonstrate how arbitrary this could be):
#define APPLY_TEST_MACROS(macro) \
macro(test_add, (int a=add(1,1); assert(a==2); )) \
macro(test_sub, (int a=sub(5,2); assert(a==3); )) \
macro(test_mul, (int a=mul(3,4); assert(a==12); ))
#define UNWRAP(...) __VA_ARGS__
#define MAKE_ASYNC_SEM(NAME_, BODY_) \
void NAME_() { \
sem_wait(&test_sem_ctl); print(#NAME_); sem_post(&test_sem_ctl); \
UNWRAP BODY_ \
sem_wait(&test_sem_ctl); \
if (0==--tests_remaining) sem_post(&test_sem_done); \
sem_post(&test_sem_ctl); \
}
#define COUNT_TESTS(NAME_, BODY_) +1
sem_t test_sem_ctl;
sem_t test_sem_done;
void init_semaphores() {
sem_init(&test_sem_ctl, 0, 1);
sem_init(&test_sem_done, 0, 0);
}
// iterate over tests to count them
unsigned int tests_remaining = APPLY_TEST_MACROS(COUNT_TESTS);
// define the tests
APPLY_TEST_MACROS(MAKE_ASYNC_SEM)
...and so forth (I'm stopping here because the idea is to convey the idea, not code it for you). The x-macro layout allows you to iterate in the preprocessor, so you can do something like spawn a thread per test; you could also just use this same approach to build an array of test functions if, say, you want to feed your tests to a thread pool.

Related

How to implement Go's defer() in C so that it allows declaring vars?

In this Modern C video there's a trick that allows to postpone execution of a code until the block/scope exits. It's used as follows:
int main()
{
int foo=0, bar;
const char *etc = "Some code before defer";
defer(profile_begin(), profile_end())
{
/* Some code, which will be automatically
* preceded by call to profile_begin() and
* followed by run of profile_end().*/
foo++;
bar = 1;
}
etc = "Some code after defer";
foo = bar + 1;
}
Implementation from the video:
#define macro_var_line(name) concat(name, __LINE__)
#define defer(start,end) for( \
int macro_var_line(done) = (start,0); \
!macro_var_line(done); \
(macro_var_line(done) += 1), end)
It's pretty simply implemented. What might be confusing is the macro_var_line(name) macro. Its purpose is to simply ensure that a temporary variable will have a unique, "obfuscated" name by adding current line number to it (of where defer is called).
However the problem is that one cannot pass code to start snippet that declares new variables, because it is pasted in the for() comma operator that uses int type (the int macro_var_line(done) = …). So it's not possible to, eg.:
defer(FILE *f = fopen("log.txt","a+"), fclose(f))
{
fprintf(f,"Some message, f=%p",f);
}
I would want to have such macro, capable of declaring new vars in start snippet. Is it achievable with standard C99, C11 or maybe some GCC extensions?
UPDATE: I've found a solution utilizing GCC nested functions. Basically, the { bblock } that's following the defer() macro becomes nested function body. And it's possible to forward declare the nested function and invoke it from before the block, i.e.:
#define defer(start,end) \
auto void var_line(routine) (void); \
start; \
/* Invoke above predeclared void routine_123(void) function */ \
var_line(routine)(); \
end; \
/* Define the nested function */ \
void var_line(routine) (void)
UPDATE2: Here's an elegant version which:
runs first leading statements as start and the last one as the end code,
runs the very first statement in its own for()/declarative space,
runs the block properly via an if(cond == 0) check/block start up.
#define defer(...) \
for (int var_line(cond) = 0; var_line(cond) == 0; ) \
for (FIRST_ARG(__VA_ARGS__); var_line(cond) == 0; ) \
for (SKIP_LAST_ARG(SKIP_FIRST_ARG(__VA_ARGS__)); \
var_line(cond) == 0; \
var_line(cond) += 1 ) \
for (int var_line(cond_int) = 0; \
var_line(cond_int) <= 1; \
var_line(cond_int) += 1 ) \
if (var_line(cond_int) == 1) \
{ \
LAST_ARG(__VA_ARGS__); \
} else if (var_line(cond_int) == 0)
As I expressed in comments, my recommendation is to avoid using such a thing in the first place. Whatever your video might have said or implied, the prevailing opinion among modern C programmers is that macro usage should be minimized. Variable-like macros should generally represent context-independent constant values, and function-like macros are usually better implemented as actual functions. That's not to say that all macro use must be avoided, but most modern C professionals look poorly on complex macros, and your defer() is complex enough to qualify.
Additionally, you do yourself no favors by trying to import the style and idioms of other languages into C. The common idioms of each language become established because they work well for that language, not, generally, because they have inherent intrinsic value. I advise you to learn C and the idioms that C programmers use, as opposed to how to write C code that looks like Go.
With that said, let's consider your defer() macro. You write,
However the problem is that one cannot pass code to start snippet that declares new variables
, but in fact the restriction is stronger than that. Because the macro uses the start argument in a comma expression (start,0), it needs to be an expression itself. Declarations or complete statements of any kind are not allowed. That's only indirectly related to that expression appearing in the first clause of a for statement's control block. (The same applies to the end argument, too.)
It may also be important to note that the macro expands to code that fails evaluate the end expression if execution of the associated statement terminates by branching out of the block via a return or goto statement, or by executing a function that does not return, such as exit() or longjmp(). Additionally, unlike with Go's defer, the end expression is evaluated in full after the provided statement -- no part of it is evaluated before, which might surprise a Go programmer. These are characteristics of the options presented below, too.
If you want to pass only the start and end as macro arguments, and you want to allow declarations to appear in start, then you could do this:
// Option 1
#define defer(start,end) start; for( \
int macro_var_line(done) = 0; \
!done; \
(macro_var_line(done) += 1), (end))
That moves start out of the for statement in the macro's replacement text, to a position where arbitrary C code may appear. Do note, however, that any variable declarations will then be scoped to the innermost containing block.
If you want to limit the scope of your declarations then there is also this alternative and variations on it, which I find much more straightforward than the original:
// Option 2
#define defer(start, end, body) { start; body end; }
You would use that like so:
defer(FILE *f = fopen("log.txt","a+"), fclose(f), // argument list continues ...
fprintf(f,"Some message, f=%p",f);
);
That is somewhat tuned to your particular example, in that it assumes that the body is given as a sequence of zero or more complete statements (which can include blocks, flow-control statements, etc). As you can see, it also requires the body to be passed as a macro argument instead of appearing after the macro invocation, but I consider that an advantage, because it facilitates recognizing the point where the deferred code kicks in.
You can simulate defer by using the __attribute__((cleanup(...))) feature of GCC and Clang. Also see this SO question about freeing a variable.
For instance:
// the following are some utility functions and macros
#define defer(fn) __attribute__((cleanup(fn)))
void cleanup_free(void* p) {
free(*((void**) p));
}
#define defer_free defer(cleanup_free)
void cleanup_file(FILE** fp) {
if (*fp == NULL) { return; }
fclose(*fp);
}
#define defer_file defer(cleanup_file)
// here's our code:
void foo(void) {
// here's some memory allocation
defer_free int* arr = malloc(sizeof(int) * 10);
if (arr == NULL) { return; }
// some file opening
defer_file FILE* fp1 = fopen("file1.txt", "rb");
if (fp1 == NULL) { return; }
// other file opening
defer_file FILE* fp2 = fopen("file2.txt", "rb");
if (fp2 == NULL) { return; }
// rest of the code
}
There is actually an effort in the standard's committee to standardize a defer feature. The paper proposal also comes with a reference implementation. The idea is to propose such a feature that may be implemented with the least compiler magic possible.
If all goes to plan, that feature could even be rebase on lambdas, if we get these into C23 in time.
You could use a trick from "Smart Template Container for C". See link.
#define c_autovar(declvar, ...) for (declvar, *_c_ii = NULL; !_c_ii; ++_c_ii, __VA_ARGS__)
Basically you declare a variable and hijack it's type to form a NULL pointer. This pointer is used as a guard to ensure that the loop is executed only once.
Incrementing NULL pointer is likely Undefined Behavior because the standard only allows to form a pointer pointing just after an object and NULL points to no object. However, it's likely run everywhere.
I guess you could get rid of UB by adding a global variable:
int defer_guard;
And setting the guard pointer to a pointer to defer_guard in the increment statement.
extern int defer_guard;
#define defer_var(declvar, cleanup) \
for (declvar, *_c_ii = NULL; \
!_c_ii; \
_c_ii = (void*)&defer_guard, cleanup)
It will work fine when invoked as:
defer_var(FILE *f = fopen("log.txt","a+"), fclose(f))
{
fprintf(f,"Some message, f=%p",f);
}
EDIT
Actually it is possible to derive a macro that will accept both expression and declaration as start. One must use two for loops instead of one.
#define DEFER(start, end) \
for (int _done = 0; !_done;) \
for (start; !(_done++); end)
int main() {
DEFER(FILE *f = fopen("log.txt","a+"), fclose(f)) {
fprintf(f,"Some message, f=%p", (void*)f);
}
FILE *f;
DEFER(f = fopen("log.txt","a+"), fclose(f)) {
fprintf(f,"Some message, f=%p", (void*)f);
}
return 0;
}

Array of macros in c -- is it possible

I was wondering if it is possible to create something like an array of macros.
I've implemented the following code which works:
struct led_cmds_
{
ioport_pin_t *commands[LED_COUNT] ;
};
struct led_cmds_ the_led_cmd_ ;
void populate() {
the_led_cmd_.commands[0] = SPECIFICPIN(0);
}
and in main:
int main(void)
{
//.....
populate();
LED_On(the_led_cmd_.commands[0]);
}
SPECIFICPIN(x) is macro defined as:
#define SPECIFICPIN(X) (LED##X##_PIN)
What I was hoping for is a way to is a way to do something like this:
#define ioport_pin_t* ARR_LED[LED_COUNT] \
for (int j = 0; j < LED_COUNT; j++) ARR_LED[j] = SPECIFICPIN(j);
and then only need to call the following when I want to use the specific pin
LED_On(ARR_LED[some_number])
when I try to do that I get an ARR_LED undeclared (first use in this function) error.
When I try to call SPECIFICPIN(x) where x is an int iterator in a for loop for example, I get an error saying something like 'LEDx_PIN' undeclared...
You need to work on your terminology. An array of macros is not possible. Macros are no data type, but rather pure text replacement before your program is actually compiled.
I guess " populate an array using macros " is what you want to do. But it is not possible to do that in a compile-time loop - What you seem to want to achieve with your ioport_pin_t macro attempt. Macros do not have the capability to expand to more instances of text elements than you have initially given. There is no such feature as looping at compile time through macro expansions and do repetitive expansion of macros.
Your for loop loops at run-time, while the macro is being expanded at compile-time. Once you have made yourself aware what is done by the preprocessor what is done by the compiler, and what is done at run-time by the finished program, you will see that will not work.
Something like
#define P(X) {(LED##X##_PIN)}
ioport_pin_t *commands[LED_COUNT] = {
P(0), P(1), P(2),......}
#undefine P
Would be the closest thing possible to what you seem to want. Note the main use of the pre-processor is not to save you typing effort - You would be better off using copy & paste in your editor, achieve the same thing and have clearer code.
An array as tofro's answer is the way to go. However in cases that couldn't be solved simply with an array then there's another way with switch
#define SPECIFICPIN(X) (LED##X##_PIN)
void setpin(int pin, int value)
{
switch (pin)
{
case 1:
SPECIFICPIN(1) = value;
doSomething(); // if needed
break;
case x: ...
default: ...
}
}

Is it OK to use a code block as an argument for a C macro?

I have a pattern that is basically some boilerplate code with a part that varies in the middle
if(condition){
struct Foo m = start_stuff();
{ m.foo = bar(1,2); m.baz = 17; } //this part varies
end_stuff();
}
Is it OK to make a macro taht takes that intermediate code block as an argument? The rules for macro expansion in C seem awfully complicated so I am not sure if there aren't any corner cases that could come and bite me in the future (in particular, I don't understand how the macro arguments are separated if my code has commas in it).
#define MY_MACRO(typ, do_stuff) do { \
if(condition){ \
struct typ m = start_stuff(); \
do_stuff; \
end_stuff(); \
} \
}while(0)
//usage
MY_MACRO(Foo, {
m.foo = bar(1,2);
m.baz = 17;
});
So far the only thing that I managed to think of is break and continue getting captured if I use looping statements in my macro and that would be an acceptable tradeoff for my particular use case.
edit: Of course, I would have used a functions if I could. The example I used in this question is simplified and doesn't showcase the bits that can only work with macro magic.
You can put a code block into a macro argument provided that it has no unguarded comma. In your example, the only comma in the argument is guarded because it is surrounded by parentheses.
Note that only parentheses guard commas. Brackets ([]) and braces ({}) do not. (And neither do angle brackets (<>) as noted in a comment.)
However, if the code block argument is the macro's last argument, you can use a variadic macro to increase flexibility. But beware: the increased flexibility also means that errors might go unnoticed. If you do this, you'll only have to make sure that the parentheses are balanced. (Again, only parentheses matter to the macro processor.)
As an alternative, you could consider using a macro that precedes your compound statement, as illustrated below. One of the pros of this is that all debuggers would still be able to step inside your compound statement, which is not the case with the compound-statement-as-macro-argument method.
//usage
MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}
Using some goto magic (yes, 'goto' may be evil in some cases, but we have few alternatives in C), the macro can be implemented as:
#define CAT(prefix, suffix) prefix ## suffix
#define _UNIQUE_LABEL(prefix, suffix) CAT(prefix, suffix)
#define UNIQUE_LABEL(prefix) _UNIQUE_LABEL(prefix, __LINE__)
#define MY_MACRO(typ, condition) if (condition) { \
struct typ m = start_stuff(); goto UNIQUE_LABEL(enter);} \
if (condition) while(1) if (1) {end_stuff(); break;} \
else UNIQUE_LABEL(enter):
Note that this has a small performance and footprint impact when compiler optimization is disabled. Also, a debugger will seem jump back to the MY_MACRO line when running calling the end_stuff() function, which is not really desirable.
Also, you might want to use the macro inside a new block scope to avoid pollution your scope with the 'm' variable:
{MY_MACRO(Foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
}}
Of course, using 'break' not inside a nested loop in the compound statement would skip the 'end_stuff()'. To allow for those to break the surrounding loop and still call 'end_stuff()', I think you'd have to enclose the compound statement with a start token and an end token as in:
#define MY_MACRO_START(typ, condition) if (condition) { \
struct typ m = start_stuff(); do {
#define MY_MACRO_EXIT goto UNIQUE_LABEL(done);} while (0); \
end_stuff(); break; \
UNIQUE_LABEL(done): end_stuff();}
MY_MACRO_START(foo, condition) {
m.foo = bar(1,2);
m.baz = 17;
} MY_MACRO_END
Note that because of the 'break' in that approach, the MY_MACRO_EXIT macro would only be usable inside a loop or switch. You could use a simpler implementation when not inside a loop:
#define MY_MACRO_EXIT_NOLOOP } while (0); end_stuff();}
I used 'condition' as a macro argument, but you may also embed it directly in the macro if desired.
You can put code block into a macro but you must be warned that it makes debugging a lot harder using a debugger. IMHO is better just to either write a function or cut'n'paste the lines of code.
How about function pointers instead (and optionally inline functions)?
void do_stuff_inner_alpha(struct Foo *m)
{
m->foo = bar(1,2); m->baz = 17;
}
void do_stuff_inner_beta(struct Foo *m)
{
m->foo = bar(9, 13); m->baz = 445;
}
typedef void(*specific_modifier_t)(struct Foo *);
void do_stuff(specific_modifier_t func)
{
if (condition){
struct Foo m = start_stuff();
func(&m); //this part varies
end_stuff();
}
}
int main(int argc, const char *argv[])
{
do_stuff(do_stuff_inner_beta);
return EXIT_SUCCESS;
}
"Is it OK?" may mean two things:
Will it work? Here the answer is generally yes, but there are pitfalls. One, as rici mentioned, is an unguarded comma. Basically, remember that macro expansion is a copy&paste operation, and the preprocessor doesn't understand the code it copies and pastes.
Is it a good idea? I'd say the answer is generally no. It makes your code unreadable and hard to maintain. In some rare cases, this may be better than alternatives, if implemented well, but that's the exception.
Note that in C++ you could use a lambda the following way:
#include <iostream>
#define MY_MACRO(body) \
setup();\
body();\
teardown();\
int main() {
int a = 1;
MY_MACRO(([&]() mutable {
std::cout << "Look, no setup" << std::endl;
a++;
}));
std::cout << "a is now " << a << std::endl;
}
If you do this, you should first consider if there should instead be a function that plainly takes the lambda:
void withSetup(std::function<void ()> callback) {
setup();
callback();
teardown();
}
int main() {
withSetup([&]() {
doStuff();
});
}
Before answering your question "is it OK to use macro" I'd like to know why you want to convert that block of code to macro. What's that you're trying to gain and at what cost?
If same block of code you're using repeatedly, it's better to convert that in a function, maybe an inline function and leave it to compiler to make it inline or not.
Should you run into crash\issue, debugging a macro is a tedious task.

Portable instrumentation

GCC has a nice feature about instrumentation which let you call a routine every time a function is called, or every time a function returns.
Now, I want to create my own system to make it portable to other compilers, and also to allow to instrumentalize the functions I want (which can vary in number of parameters), so I was thinking in two macro for both situations. I am thinking in making some kind of profile that it is activated only with a define clause.
#define FUNCT(t,function_name,...) \
(t) function_name(...) { \
(void) *func_pointer = &(function_name); \
start_data(func_pointer, myclock());
#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}
FUNCT(BOOL, LMP, const int prof, const int nmo))
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
RETURN(FALSE);
}
... do more....
RETURN(TRUE);
}
but I can’t get it to work. Can someone help me with this? or is this a difficult task to accomplish?
Other alternative that comes to my mind is let the function declare without a macro, and if it is anyway to know the function pointer without knowing its name, something like in VB when you call a Form with Me, with it is a generic alias. is it possible?
Use gcc -E to debug your macros. Using the code you posted:
$ gcc -E t.c
# ... skip stuff ....
(BOOL) LMP(...) { (void) *func_pointer = &(LMP);
start_data(func_pointer, myclock());)
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
{stop_data(func_pointer, myclock()); return (FALSE);};
}
... do more....
{stop_data(func_pointer, myclock()); return (TRUE);};
}
(I added some whitespace to make it readable.)
You can see two problems immediately: function arguments didn't get expanded as you thought they would, and there's an extra ) from somewhere.
To get the expanded variadic arguments, use __VA_ARGS__, not .... The stray ) is at the call site.
So:
#define FUNCT(t,function_name,...) \
(t) function_name(__VA_ARGS__) { \
(void) *func_pointer = &(function_name); \
start_data(func_pointer, myclock());
#define RETURN(x) {stop_data(func_pointer, myclock()); return (x);}
FUNCT(BOOL, LMP, const int prof, const int nmo)
if (nmo <= 5 ||
prof > (prof_l / 3)) {
.... do long operations....
RETURN(FALSE);
}
... do more....
RETURN(TRUE);
}
As to whether this is worth trying (variadic macros came with C99, not all compilers implement that standard, and support might vary from compiler to compiler), I'm not certain. You are probably better off using each compiler's native profiling tools - you'll get better results with hopefully less overhead.
It is much easier to instrument your functions at the calling side instead of the function side. A macro can have the same name as a function. Declare your replacement function somewhere
double myfunc_wrapper(int someArg) {
double ret = 0;
// do something before
...
// now call it
ret = (myfunc)(someArg);
// Then do something after
....
return ret;
}
Just to be sure put the () arround the call itself to be sure that always a function is called and not a macro.
And then "overload" your function with a macro
#define myfunc(...) mfunc_wrapper(__VA_ARGS__)
with that idea you can replace your function on the fly in the compilation units that interes you.
in addition to Mat, there is a ergonimical problem with using #define RETURN(x) {...}:
if (test)
RETURN (TRUE);
else
RETURN (FALSE);
will evaluate to
if (test)
{...}
; // <syntactical error
else
{...}
;

Variable no of argument in C Macro

I am writing some hardware specific code, where I want to use C Macros, the macro definition would be something like this:-
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1) if(a[MODE][RESOURCE1] != x1) || \
(a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3;
Since sometimes I can have more then 1 resource to allocate, such as:-
#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) if(a[MODE][RESOURCE1] != x1) || \
(a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3;
if(a[MODE][RESOURCE2] != x1) || \
(a[MODE][RESOURCE2] != y1)) \
a[MODE][RESOURCE2]=x3;
Is there any way I can write a macro, which covers both cases, as it takes variable number of arguments?
I have used variable number of arguments, in macro for printf macros, but then how I will address those arguments, by their respective name, for example, if I modify the MACRO definition such as:0-
#define VALIDA_RESOURCE_AND_ALLOCATE(MODE,.....)
How will I identify RESOURCE1, RESOURCE2?
Your macros have a lot of repeated code in them. Simplifying them helps make a solution more apparent:
#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) do {\
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE1); \
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE2); \
} while(0)
Here, it's clearer that this is simply a repeated invocation of the first macro while iterating through a list of arguments.
Assuming you know that the data types being used here will always be consistent, you can try something like this (untested and written off of the top of my head):
#ifdef HARDWARE_PLATFORM_A
static sometype args[] = {
RESOURCE1,
RESOURCE2,
/* ... etc, etc */
};
#elif defined HARDWARE_PLATFORM_B
static sometype args[] = {
RESOURCE10,
RESOURCE11,
/* ... etc, etc */
};
/* repeat for all hardware platforms */
#endif
void initialization_function (void) {
int i;
for (i = 0; i < (sizeof(args) / sizeof(args[0])); ++i) {
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, args[i]);
}
}
where sometype is the data type of the arguments that you will be using for RESOURCE1, RESOURCE2, etc.
Given the complexity of what you are trying to do, you'd be a lot better off writing a function to do the iteration instead of a macro. You can still use a macro to create the RESOURCE list, but don't try to get the pre-processor to do the iteration for you. If you need to avoid the overhead of a function call (since you tagged this as 'embedded'), you can declare the functions inline and the result should be as efficient as using a macro. In the process, though, you'll gain things like type safety.
While it might be technically possible to do this with a macro, it would be a nasty hack that would most likely bring more problems than benefits. Doing complex procedural tasks with the pre-processor rarely turns out well.
The other alternative that you have is to use a code generator that takes a list of RESOURCE arguments from a file and generates a .c file containing the initialization code. The code generator would be written in a language much more powerful than the C pre-processor (almost any scripting language could be used here). This probably wouldn't be worth the trouble unless you had a long list of RESOURCEs, though.
One way you could accomplish it is don't pass in a variable number of arguments, but stick with two and make the second one be a list that can be used in an initialization. For example (trailing backslashes left off for clarity):
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE, LIST)
{
int resources[] = LIST;
int count;
for(count = 0; count < sizeof(resources)/sizeof(int); count++) {
/* do stuff here for each resources[count] */
}
}
And then you can simply call it as such:
VALIDATE_RESOURCE_AND_ALLOCATE(MODE, { RESOURCE1, RESOURCE2 } )
Note: there is more than one way to skin this cat, so pick your favorite answer and go with it :-)
Would this be too silly? ;-)
#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1,RESOURCE2) \
if(a[MODE][RESOURCE1] != x1) || (a[MODE][RESOURCE1] != y1)) \
a[MODE][RESOURCE1]=x3; \
if((RESOURCE1 != RESOURCE2) && (a[MODE][RESOURCE2] != x1) || (a[MODE][RESOURCE2] != y1))) \
a[MODE][RESOURCE2]=x3;
and Call it as below for single resource
VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R1)
and like below for two?
VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R2)

Resources