简体   繁体   中英

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 RESOURCE s, 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM