tlehman
tlehman

Reputation: 5167

Simulating scope in C macros

I have the following macro to print out the contents of an array of integers for debug purposes:

#define PRINT_ARRAY(ary, num)        \
    int ai = 0;                      \
    printf("{");                     \
    for(ai=0; ai < num; ++ai) {      \
        printf("%d", ary[ai]);       \
        if(ai < num-1) printf(", "); \
    }                                \
    printf("}\n");

The problem I am having is that when I use it more than once, some compilers complain that I am redefining ai.

Is there a way to make the identifier different for each invocation of the macro? I can come up with a naming scheme that would have a very low change of name collisions, but I'd like to make it automatic.

I know I could use a function, but I am still curious, since I would like to know if there is a way to do this with macros.

Upvotes: 3

Views: 90

Answers (3)

griffin
griffin

Reputation: 1258

You can just put it into it's own scope, e.g. surround it with { and }

Like this:

#define PRINT_ARRAY(ary, num)        \
{                                \
    int ai = 0;                      \
    printf("{");                     \
    for(ai=0; ai < (num); ++ai) {      \
        printf("%d", ary[ai]);       \
        if(ai < (num)-1) printf(", "); \
    }                                \
    printf("}\n");                   \
}

I also added parantheses around the num parameter, so you can use a complex expression without having strange sideffects.

WRT to your identifier naming:

You can use macro expansion to change the name using a parameter, but as there are not counter or loop constructs in all c preprocessors I know, I don't think it's possible to automatically change the identifier after every user. Another way would be to have the macro redefine itself every time, but afaik that's also not possible.

Edit:

As has been pointed out (thanks to Aaron McDaid, also see the link he posteed: https://stackoverflow.com/a/1067238/146041), you should use a do { } while(0) construct around your code, so your macro would become:

#define PRINT_ARRAY(ary, num)        \
do {                                \
    int ai = 0;                      \
    printf("{");                     \
    for(ai=0; ai < (num); ++ai) {      \
        printf("%d", ary[ai]);       \
        if(ai < (num)-1) printf(", "); \
    }                                \
    printf("}\n");                   \
} while(0)

Upvotes: 2

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726987

If your C is C99-compliant, put ai's declaration in the for loop's header. You should also surround the code with do / while(0)

#define PRINT_ARRAY(ary, num)        \
    do {printf("{");                     \
    for(int ai=0; ai < num; ++ai) {      \
        printf("%d", ary[ai]);       \
        if(ai < num-1) printf(", "); \
    }                                \
    printf("}\n"); } while(0)

so that it could be used after control structures without surrounding it with curly braces.

Upvotes: 2

user405725
user405725

Reputation:

Why don't you use a classic do-while trick? For example:

#define FOO(EXPR) \
  do { \
    (EXPR); \
  } while(0)

Upvotes: 6

Related Questions