2012-04-24 33 views
3

在一個示例項目,我定義的宏使用#定義列表作爲輸入到一個C預處理宏

#define FOO(x, y) x + y . 

這工作得很好。例如,FOO(42, 1337)評估爲1379

不過,我現在想用另一個#define

#define SAMPLE 42, 1337 

當我現在請FOO(SAMPLE),這是不行的。編譯器告訴我FOO有兩個參數,但只有一個參數被調用。

我想這是因爲,雖然宏的參數是在函數本身之前進行評估的,但預處理器在評估之後不會再分析整個指令。這類似於不能從宏輸出額外的預處理器指令的事實。

有沒有可能獲得所需的功能?

用C函數代替FOO宏是不可能的。原始宏位於我無法更改的第三方代碼中,並且它輸出逗號分隔的值列表,以便在數組初始化器中直接使用。因此,C函數不能複製相同的行爲。

如果通過簡單的方法無法完成此任務:您將如何將(x, y)對以可維護的形式存儲?就我而言,有8個參數。因此,將各個零件存放在單獨的#define-s中也不易維護。

+5

'FOO(42,1337)'不評估爲1379,它評估爲「42 + 1337」。預處理器僅執行文本替換。之後,當編譯器執行[常量摺疊](http://en.wikipedia.org/wiki/Constant_folding)時,是否進行了這種替換。 – 2012-04-24 21:20:36

+1

重複的[是否有可能宏評估多個參數到另一個?](http://stackoverflow.com/questions/10234172/is-it-possible-to-a-macro-evaluate-multiple-arguments-to-另一個) – 2012-04-24 21:46:30

+0

@Adam:true :-)然而,正如詹姆斯指出的那樣,我的問題是另一回事。我不是在刪除這個問題,以防其他人通過使用不同的關鍵字找到它。但是,投票結束。 – Etan 2012-04-24 21:49:54

回答

4

您遇到的問題是預處理器不匹配並按所需順序擴展宏。現在你通常可以通過插入一些額外的宏來迫使它獲得正確的訂單來達到你想要的目的,但爲了達到這個目的,你需要了解正常順序是什麼。

  • 當編譯器看到帶有參數,然後在參數列表(它首先掃描,分解成參數不承認或擴大在參數中的任何一個宏宏的名稱。

  • 解析和分離的參數之後,然後重新掃描的宏每個參數,並擴展任何它找到withing的參數,除非該參數在宏體使用###

  • 它然後替換每個(現在可能擴展)參數的實例中的參數實例

  • 最後,它重新掃描任何其他可能存在於擴展主體的宏的主體。在這一次掃描,原來的宏將無法識別和再次膨脹,所以你不能有遞歸宏擴展

所以,你可以得到由謹慎使用一個展開宏接受一個你想要的效果參數,並將其擴展,讓您在這個過程中強制額外的擴展在正確的點:

#define EXPAND(X) X 
#define FOO(x,y) x + y 
#define SAMPLE  42, 1337 

EXPAND(FOO EXPAND((SAMPLE))) 

在這種情況下,你第一次明確地擴大其在參數列表宏,然後手動事後擴大導致宏調用。

更新的問題海報

#define INVOKE(macro, ...) macro(__VA_ARGS__) 

INVOKE(FOO, SAMPLE) 

規定,沒有與EXPAND小號弄亂代碼工作的擴展解決方案。

+0

用我的最終解決方案更新了您的答案。對不起,但註釋不允許代碼區域插入單獨的行。 – Etan 2012-04-25 08:29:55

+1

'INVOKE'宏甚至不需要額外的'EXPAND'調用,因爲'INVOKE'自身的擴展可以滿足您的所有需求。 – 2012-04-25 16:49:59

+0

true:)......... – Etan 2012-04-27 07:54:23