简体   繁体   中英

C recursive preprocessor define

I have incorporated libiniparser library in to my Android NDK application. One problem this library write logs directly to stdout / stderr .

I did not want to heavily modify the code so I wrote a macro to log in logcat

#include <android/log.h>

#define LOG_TAG   "libinipaser"

#define fprintf(pipe,...) \
    if (pipe == stdout) \
        __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__); \
    else if (pipe == stderr) \
        __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__); \
    else \
        fprintf(pipe,__VA_ARGS__)

Until the last moment I was not sure it would work, but it works. I have checked preprocessor output (gcc -E) it looks like I expected

fprintf(f, "[%s]=[%s]\n", d->key[i], d->val[i]);

line above after preprocessing looks:

if (f == (&__sF[1])) __android_log_print(ANDROID_LOG_INFO,"libinipaser","[%s]=[%s]\n", d->key[i], d->val[i]); else if (f == (&__sF[2])) __android_log_print(ANDROID_LOG_ERROR,"libinipaser","[%s]=[%s]\n", d->key[i], d->val[i]); else fprintf(f,"[%s]=[%s]\n", d->key[i], d->val[i]);

Could someone explain:

  1. Does c-preprocessor support recursive macros?
  2. How it happened that the LOG_TAG define was replaced but inner fprintf wasn't?
  3. Will this define works everywhere?
  4. Is this a good approach at all or not?
  1. No, the c preprocessor doesn't "support" recursive macros, which in your case means that it does exactly what you want, instead of expanding the macro recursively (which wouldn't ever terminate).
  2. The preprocessor doesn't expand tokens that already have been expanded previously in the current expansion.
  3. I think so. According to https://gcc.gnu.org/onlinedocs/cpp/Traditional-macros.html , this behaviour seems to be part of the ISO C standard (where the "traditional mode" means the mode that was used before the ISO C89 standard).
  4. It looks quite sensible to me.

I'll answer question 4 only. mstorsjo has the rest pretty much taped.

No. It's not really a good idea. Macro Magic is generally discouraged where there's another 'proper' way to achieve the result - that might be a constant or a function (as in this case).

In this case what appears to be a call to fprintf that (normally) returns an int (the count of characters output) will not evaluate to that. For example, int count=fprintf(file,"Hello"); will be a compilation error.

That might not be a problem for you, but considering the general case, anyone who has any code in a translation unit including that macro definition may have just had their code broken and have a Dickens of a job finding the cause and then need to #undefine the macro to get their code back!

Marcos aren't bad. They definitely have their place in conditional compilation and debugging in particular. Personally I miss them for that purpose in Java.

However, as a general rule, if there's another language construct to do the same thing - use it.

There's some excellent answers discussing the merits and dismerits of macros here:

Why are preprocessor macros evil and what are the alternatives?

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