2011-06-15 65 views
4

我想在C文件上運行工具x並獲得後宏代碼。 (如果我們只能像宏一樣更好地工作)。我知道gcc -E,但那也包含在一個大文件中。有沒有辦法將C宏替換爲正常的C代碼

基本上我想使用一些C宏重複的代碼,但不希望最後的代碼包含任何的宏,因爲它們經項目皺起了眉頭。

+1

是不是'gcc -E'? – littleadv 2011-06-15 05:37:07

+0

不,因爲我提到gcc -E不包含文件。我想要一個自動重新格式化後可用的結果文件。 – 2011-06-15 05:39:57

+1

我的意思是,你在問題中寫了'gcc -F',我認爲你的意思是'gcc -E' ... :-) – littleadv 2011-06-15 05:43:46

回答

3

使用您選擇的腳本語言,註釋掉所有#include s,然後運行gcc -E -Wp,-P,-C,-CC foo.c,然後取消註釋#include s。或者,您可以將#include替換爲一些不以#開頭的字符串,例如include#@include;可能性是無止境。使用@代替#的方法讓您完全控制了該預處理指令做,沒有得到擴大...代碼你不想@擴大了的人,然後將腳本只是執行gcc -E,然後改變@#。不過,我認爲最好反過來使用特殊標記(例如,@)來指示您的可展開宏。然後,腳本會將前導# s變成其他內容(例如,HIDE#),並將標記(例如@)變爲#,運行gcc -E,然後將HIDE#(或其他)轉回#

-Wp指定預處理器選項。 -P表示不生成行指令,-C表示不刪除註釋,而-CC表示不刪除由宏生成的註釋 - 這意味着代碼生成宏中的註釋將保留在輸出中。要確定所有可用的預處理器選項(有很多,大多不感興趣),運行gcc -Wp,--help anyfile.c ...這就是我所做的拿出這個答案(後第一次運行gcc --help找到-Wp選項)。 (知道如何找東西出來比知道更重要的東西。)

2

如何在#include列表後面的代碼中添加分隔符,以便您可以手動刪除包含文件擴展,但在運行gcc -E後宏擴展完好無損?

喜歡的東西:

#include <one> 
#include <two> 
void delete_everything_above_and_put_includes_back(); // delimeter 
#define MACRO(X) ... 
//rest of the code 

我不知道,擴展宏,但不擴大#include個工具...

+0

有趣的想法。 – 2011-06-15 05:54:24

+0

這不起作用,因爲它擴展了頭文件中定義的所有宏,而不僅僅是本地宏。有一種更簡單的方法...查看我的答案。 – 2011-06-15 08:05:03

+0

@Jim嗯......我假定宏定義在一個頭文件中,但是又一次 - 你可以完全刪除'#include'行,並在完成後將它們放回,並得到相同的結果,而不會擴大不需要的宏。我個人不喜歡命令行參數,越少越好,你必須在運行腳本之後編輯文件,所以並不重要。 – littleadv 2011-06-15 08:10:37

1

我決定再添加一個答案,因爲它是完全不同的。

而不是有技巧將宏展開到項目源存儲庫 - 你有沒有考慮使用const變量和inline函數作爲替代?

基本上這些都是宏在您的項目「時皺眉」的原因。

你必須記住,inline僅僅是「建議」(即:該功能可能無法其實內聯)和const會使用,而不是作爲一個常量文字記憶(當然,依賴於編譯器,編譯好將優化),但會做兩兩件事:

  1. 保持你的代碼遵守項目編碼標準(這永遠是一件好事,至少在政治上如果不一定是技術上的)
  2. 不需要額外的隱藏腳本或行爲來代表您保持代碼的可重用性和可維護性(我假設您想要使用宏以避免重複代碼,對嗎?)

因此k作爲一種選擇,也要考慮到這一點。

+0

+1從另一個線程的交換中提取肉,並將其轉化爲一個堅實的答案...做得很好......並超越了所述的問題,到了元問題......一個例子XY問題(http://www.google.com/search?q=X-Y+problem)。 – 2011-06-15 10:24:06

+0

很多這些都不是常數或者很容易在c函數中實現的東西。在函數調用任意數量的參數之前或之後添加代碼非常困難,除了宏(使用#define M(f,a)... ret_val = func args ...「M(func_x,(argy, argz))「擴展爲」func_x(argy,argz)「技巧 – 2011-06-22 07:20:07

0

作爲一種可能的解決問題的方法:「寫一個宏,然後將其丟棄,由等效功能替代」,你可以使用原型函數宏。他們有一些限制,必須小心使用。但它們的功能幾乎與功能一樣。

#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA 

xxPseudoPrototype(float, xxSUM_data, int x; float y;); 
xxSUM_data xxsum; 
#define SUM_intfloat(X, Y) (xxsum = (xxSUM_data){ .x = (X), .y = (Y) }, \ 
    xxsum.xxmacro__ret__ = xxsum.x + xxsum.y, \ 
    xxsum.xxmacro__ret__) 

我已解釋這裏的細節(主要部4,對於函數宏):

Macros faking functions

  • 的第一線定義了可以用於聲明pseudoprototypes宏宏爲
  • 第二行使用該宏提供這樣的假原型。它定義了所需類型的「正式」參數。它依次包含宏所需的「return」類型,宏的參數所在的結構的名稱以及宏的參數(帶有類型!)。我更喜歡打電話給他們假參數
  • 第三行是一個強制性聲明,它使「真實」假參數。它聲明瞭一個結構體,它有必要寫。它定義了一個包含僞參數「真實」版本的結構。
  • 最後,將它自己的宏定義爲表達式鏈表,用逗號分隔。第一個操作數用於將宏的參數「加載」到「真實」類型參數中。最後一個操作數是「返回值」,它也有所需的類型。

觀察該編譯器的類型權和透明的診斷。
(但是,有必要對這些結構有所關注,如鏈接所述)。

現在,如果您可以收集宏的所有語句作爲由逗號分隔的函數調用鏈,那麼您可以根據需要獲取函數式宏。

此外,由於已經定義了參數列表,因此可以輕鬆將其轉換爲實際函數。類型檢查已經完成,所以一切都會正常工作。 在上面的例子中,必須更換所有的行(第一個除外),由這些其他的:

#define xxPseudoPrototype(RETTYPE, MACRODATA, ARGS) typedef struct { RETTYPE xxmacro__ret__; ARGS } MACRODATA 

float SUM_intfloat(int x, float y) {      /* (1) */ 
    xxPseudoPrototype(float, xxSUM_data, int x; float y;); /* (2) */ 
    xxSUM_data xxsum;          /* (2) */ 
    return             /* (3) */ 
    (xxsum = (xxSUM_data){ .x = x, .y = y },    /* (4) (5) (6) */ 
     xxsum.xxmacro__ret__ = xxsum.x + xxsum.y,   /* (5) (6) */ 
     xxsum.xxmacro__ret__)        /* (6) */ 
    ;              /* (7) */ 
}               /* (8) */ 

替換將遵循sistematic過程:

(1)宏頭變成函數頭。分號(;)替換爲逗號(,)。
(2)聲明行在函數體內移動。
(3)添加「返回」單詞。 (4)宏參數X,Y被函數參數x,y替換。
(5)所有結尾的「\」被刪除。
(6)所有中介計算和函數調用都保持不變。
(7)添加分號。
(8)關閉功能體。

問題:雖然這種方法可以解決您的需求,但請注意該函數已重複其參數列表。這是不好的:假的原型和副本必須被刪除:

float SUM_intfloat(int x, float y) { 
    return 
    (x + y) 
    ; 
}  
相關問題