2010-10-07 73 views
1

我正在使用BOOST_PP在預處理器中執行預編譯計算。我專注於代碼大小爲非常重要的應用程序。 (所以請不要說編譯器應該通常這樣做,我需要控制什麼在編譯時執行和什麼代碼生成)。但是,我希望能夠爲整數常量和變量使用相同的宏/函數名稱。作爲簡單的例子,我可以有在Boost預處理器中混合變量和整型常量

#define TWICE(n) BOOST_PP_MUL(n,2) 
//..... 
// somewhere else in code 
int a = TWICE(5); 

這做什麼,我也想,在編譯時評價到

int a = 10; 

不過,我也希望它在

int b = 5; 
int a = TWICE(b); 

使用這應該是預處理,

int b = 5; 
int a = 5 * 2; 

當然,我可以使用傳統的宏像

#define TWICE(n) n * 2 
這樣做

但它然後不做我想要它做的整型常量(在編譯時評估它們)。

所以,我的問題是,是否有一個技巧來檢查參數是文字還是變量,然後使用不同的定義。即是這樣的:

#define TWICE(n) BOOST_PP_IF(_IS_CONSTANT(n), \ 
           BOOST_PP_MUL(n,2), \ 
           n * 2) 

編輯: 那麼我真的是經過一些方法來檢查,如果事情是一個常數可以在編譯的時候,因此一個很好的理由爲BOOST_PP_功能。我意識到這與大多數人對預處理器和一般編程建議的期望不同。但是沒有錯誤編程方式,所以如果你不同意它的理念,請不要討厭這個問題。 BOOST_PP庫存在的原因是存在的,這個問題本質上是一致的。它可能只是不可能的。

+0

你可以通過使用模板而不是預處理器來獲得這個 – Anycorn 2010-10-07 18:08:49

+0

@aaa可以模板選擇常量嗎?如果可以的話,我很樂意(即使模板需要C++編譯)。但我堅持如何編寫這樣的模板。 – highBandWidth 2010-10-07 18:13:21

+1

作爲替代方案,您是否已將http://www.boost.org/doc/libs/1_44_0/libs/wave/index.html – Anycorn 2010-10-07 18:39:22

回答

2

你正試圖做一些更好的事情,留給編譯器的優化。

int main (void) { 
    int b = 5; 
    int a = b * 2; 

    return a; // return it so we use a and it's not optimized away 
} 

GCC -O3 -s T.C

.file "t.c" 
.text 
.p2align 4,,15 
.globl main 
.type main, @function 
main: 
.LFB0: 
.cfi_startproc 
movl $10, %eax 
ret 
.cfi_endproc 
.LFE0: 
.size main, .-main 
.ident "GCC: (Debian 4.5.0-6) 4.5.1 20100617 (prerelease)" 
.section .note.GNU-stack,"",@progbits 

優化編譯器將優化。

編輯:我知道你不想聽到編譯器「應該」或「通常」這樣做。但是,你所要做的並不是要在C預處​​理器中完成的任務;設計C語言的人員和C預處理器將其設計爲與預處理令牌一起工作,因爲它是基本原子。 CPP在很多方面都是「愚蠢的」。這並不是一件壞事(事實上,這在很多情況下使得它非常有用),但是在一天結束時,它是一個預處理器。它在分析之前預處理源文件。它在語義分析發生之前預處理源文件。它在檢查給定源文件的有效性之前預處理源文件。我知道你不想聽到這是解析器和語義分析器應該處理或通常做的事情。但是,這是現實情況。如果你想設計的代碼非常小,那麼你應該依靠你的編譯器來完成它的工作,而不是試圖創建預處理器結構來完成這項工作。這樣想:數千小時的工作進入你的編譯器,所以儘量重複儘可能多的工作!

+0

謝謝!我喜歡你的答案。看到彙編代碼,我可以看到編譯器確實對其進行了優化。我不確定它是否會對高階函數以及涉及控制邏輯的位置這樣做。但要看到的唯一途徑是通過實驗,所以我會回去看看,因爲我感興趣的功能。 – highBandWidth 2010-10-08 20:31:35

+0

在這裏做的最好的事情就是進行實驗。如果您使用GCC或鏗鏘,還有的在其中您可以檢查一下編譯器是做什麼的編譯器是不是做的方式一大堆。你甚至可能想看看clang靜態分析器,這是一個非常酷的工具,用於檢查如何編譯C或C++源代碼。 Visual Studio也爲這類東西提供了極好的工具。 – wash 2010-10-08 20:39:17

+0

http://clang-analyzer.llvm.org/ < - 鏈接到鐺靜態分析器。 – wash 2010-10-08 20:41:50

1

不是很直接的方法,但是:

struct operation { 
    template<int N> 
    struct compile { 
     static const int value = N; 
    }; 
    static int runtime(int N) { return N; } 
}; 

operation::compile<5>::value; 
operation::runtime(5); 

或者

operation<5>(); 
operation(5); 
+0

嗯,它仍然看起來像兩個功能,叫不同。它們似乎只駐留在同一個結構中。我可以製作兩個不同的宏,就像在我的例子中一樣,只需調用合適的宏,具體取決於我是否需要編譯時或運行時計算。我實際上是瞄準一個界面,選擇正確的代碼。 – highBandWidth 2010-10-07 18:50:51

+1

@highBandWidth啊好吧,我看...可能很難做 – Anycorn 2010-10-07 18:56:13

1

有兩個層次(預處理和變量的評價)將沒有真正的機會。從我的理解來看,b應該是一個符號常量?

我認爲你應該使用傳統的一個

#define TWICE(n) ((n) * 2) 

但隨後而不是用表情初始化變量,你應該編譯時間常數初始化。我看到在編譯時強制執行評估以及在C中具有符號常量的唯一東西是整型枚舉常量。這些被定義爲具有類型int並在編譯時進行評估。

enum { bInit = 5 }; 
int b = bInit; 
enum { aInit = TWICE(bInit) }; 
int a = aInit; 

而且一般你不應該有太const節儉(爲您b),並與-S檢查產生的彙編。

+0

我明白你的意思了。我實際上正在嘗試編寫一個代碼大小非常重要的庫,並且我試圖給出一個可以用常量和變量調用的接口。在這種情況下,它們可能是真實的變量,必須在運行時進行評估。可能是無法完成的。 – highBandWidth 2010-10-08 15:27:04

+0

@highBandWidth:如果這對你來說非常重要,那麼你應該真正確定這些是編譯時表達式的點,並且在我的答案中做這些。如果這樣做,編譯器會立即告訴你,如果你試圖聲明枚舉與動態表情不變,所以這是很好的測試。對於其他地方你不能進行運行時評估,所以無論如何你必須使用經典的宏。 – 2010-10-08 16:11:54

+0

我同意。我試圖編寫一個庫,所以我沒有選擇檢查編譯時問題,然後回去更改代碼。 – highBandWidth 2010-10-08 20:28:26