2014-11-25 76 views
2

我已將libiniparser庫合併到我的Android NDK應用程序中。這個庫的一個問題是直接寫日誌到stdout/stderrC遞歸預處理器定義

我不想大量修改代碼,所以我寫了一個宏登錄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__) 

直到最後一刻,我不知道它會工作,但它的作品。我已籤預處理器輸出(GCC-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. 請問C預支持遞歸宏?
  2. 它是如何發生的LOG_TAG定義被替換,但內部fprintf不是?
  3. 這個定義會在任何地方工作嗎?
  4. 這是一個好方法嗎?
+2

這很簡單,C預處理沒有遞歸的宏。 ([Wikipedia reference。](http://en.wikipedia.org/wiki/C_preprocessor#Other_uses)) – 2014-11-25 10:02:01

回答

5
  1. 沒有,C預處理不「支持」遞歸宏,而你的情況意味着它不正是你想要的東西,而不是擴大宏觀遞歸(這不會永遠終止)。
  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");將是一個編譯錯誤。

這對您來說可能不是問題,但考慮到一般情況,任何在翻譯單元中包含該宏定義的任何代碼的人可能已經破譯了他們的代碼,並且找到了找到原因的Dickens工作,那麼需要#undefine這個宏讓他們的代碼回來!

馬科斯並不差。它們在條件編譯和調試中絕對佔有一席之地。就我個人而言,我爲了這個目的而想念他們。

但是,作爲一般規則,如果有另一種語言結構來做同樣的事情 - 使用它。

這裏有討論宏的優點和dismerits一些優秀的答案:

Why are preprocessor macros evil and what are the alternatives?