2014-11-25 6 views
2

Я включил библиотеку libiniparser в приложение для Android NDK. Одна из проблем в этой библиотеке записывает журналы непосредственно на stdout/stderr.Рекурсивный препроцессор C определяет

Я не хотел сильно изменить код, так что я написал макрос, чтобы войти 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__) 

До последнего момента я не был уверен, что это будет работать, но это работает. Выход я проверил препроцессор (НКА -E) это выглядит, как я ожидал

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

линии выше после предварительной обработки выглядит:

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]); 

Может кто-то объяснить:

  1. Поддерживает ли С-препроцессор рекурсивные макросы?
  2. Как получилось, что было определено LOG_TAG, но внутреннее fprintf не было?
  3. Будет ли это определять работу везде?
  4. Это хороший подход вообще или нет?
+2

Это просто, C препроцессор не рекурсивные макросы. ([Ссылка в Википедии.] (Http://en.wikipedia.org/wiki/C_preprocessor#Other_uses)) –

ответ

5
  1. Нет, с препроцессор не «поддерживает» рекурсивных макросов, которые в вашем случае означает, что он делает именно то, что вы хотите, вместо того, чтобы расширить макрос рекурсивно (который бы никогда не прекращается).
  2. Препроцессор не расширяет токены, которые уже были расширены ранее в текущем расширении.
  3. думаю. Согласно https://gcc.gnu.org/onlinedocs/cpp/Traditional-macros.html, это поведение, как представляется, является частью стандарта ISO C (где «традиционный режим» означает режим, который использовался до стандарта ISO C89).
  4. Это выглядит очень разумно для меня.
2

Ответ на вопрос 4 только. У mstorsjo остальное довольно много.

Нет. Это не очень хорошая идея. Макро-магия, как правило, обескуражена там, где есть еще один «правильный» способ достижения результата - это может быть константа или функция (как в этом случае).

В этом случае то, что кажется вызовом fprintf, которое (обычно) возвращает int (количество выводимых символов), не будет оценивать это. Например, int count=fprintf(file,"Hello"); будет ошибкой компиляции.

Это не проблема для вас, но, учитывая общий случай, любой, у кого есть какой-либо код в единицах перевода, включая это определение макроса, возможно, только что их код сломан и у Диккенса есть работа, то нужно сделать #undefine макросом, чтобы вернуть код!

Маркос не плох. Они определенно имеют свое место в условной компиляции и, в частности, отладке. Лично я пропускаю их для этой цели на Java.

Однако, как правило, если есть другая языковая конструкция, чтобы сделать то же самое - используйте ее.

Там какая-то отличные ответы обсуждают достоинства и dismerits макросов здесь:

Why are preprocessor macros evil and what are the alternatives?

Смежные вопросы