2011-07-03 118 views
12

如果我寫編譯時間評估

enum chars = digits ~ uppercase; 

將字符串在編譯時串連?我假設它會。如果我用字符串文字或CTFE函數替換它,我無法測量任何顯着的性能差異(甚至稱它爲一億次)。如果我用const替換枚舉,我確實有區別。我被告知這樣寫是沒有效率的。我認爲這樣很方便,我沒有看到效率低下。 (順便說一下,該行是在遞歸調用的函數中)。

的完整代碼(轉換爲數字系統具有不同的基本)

import std.string; 

string toBase(long n, int b) 
in { 
    assert(2 <= b && b <= 35); 
} body { 
    static string sign; 
    if (n < 0) { 
     n *= -1; 
     sign = "-"; 
    } 
    enum chars = digits ~ uppercase; 
    size_t r = cast(size_t)(n % b); 
    if (n == r) { 
     return sign ~ chars[r]; 
    } 
    return toBase((n - r)/b, b) ~ chars[r]; 
} 

編輯:更新的代碼,響應於註釋,不相關的問題

string toBase(long n, int b) 
in { 
    assert(2 <= b && b <= 35); 
} body { 
    enum chars = digits ~ uppercase; 
    long r = n % b; 
    char c = chars[cast(size_t) abs(r)]; 
    if (n == r) { 
     return (n < 0 ? "-" : "") ~ c; 
    } 
    return toBase((n - r)/b, b) ~ c; 
} 
+2

您忘記了重置符號字符串(您可以使用'scope(exit)sign =「」;'),所以'toBase(-10,10)'後跟'toBase(10,10)'會給相同的結果 –

+0

沒錯。哈哈哈,我第一次使用靜態變量。棘手。這個範圍(退出)的東西真的很有用,不是嗎?遞歸調用不符合範圍退出條件,我感到有點驚訝。 – fwend

+1

作用域(退出)在當前堆棧框被彈出堆棧時執行(如try ... finally真的但沒有額外的縮進)遞歸不會這樣做 –

回答

9

enum實例像即總是在編譯時評估(並且在編譯時不可能評估時拋出編譯錯誤)

所以串接在編譯時完成的和不可改變的版本存儲在代碼和引用在運行時檢查自己的字符串是否是在編譯時串連

5

一種方法是編譯代碼,並檢查目標文件。假設你的文件被稱爲test.d

dmd -c test.d 
objdump test.o | grep -C3 "" 

...應該產生這樣的:

Contents of section .rodata: 
0000 2d000000 00000000 00000000 00000000 -............... 
0010 01000000 00000000 00000000 00000000 ................ 
0020 30313233 34353637 38394142 43444546ABCDEF 
0030 4748494a 4b4c4d4e 4f505152 53545556 GHIJKLMNOPQRSTUV 
0040 5758595a 00000000 00000000 00000000 WXYZ............ 
0050 24000000 00000000 20000000 00000000 $....... ....... 

(這是在Linux上,在其他平臺上,你需要不同的工具來檢查目標文件。)

如果您改變enumconststring,你會(可能)沒有得到輸出:不會有任何連接字符串爲grep找到。

但編譯器可能會在編譯時連接字符串,即使不使用enum也是如此。考慮此方案:

import std.stdio; 

enum a = "Aaaa"; 
enum b = "Bbbb"; 
enum c = "Cccc"; 

void main() 
{ 
    enum x = a ~ b; 
    const y = b ~ a; 
    string z = a ~ c; 
    writeln(x, y, z); 
} 

現在,編譯它,並檢查對象文件:

% dmd -c test2.d && objdump -s test2.o | egrep "(Aaaa|Bbbb)" 
0000 42626262 41616161 00000000 00000000 BbbbAaaa........ 
0020 41616161 43636363 00000000 00000000 AaaaCccc........ 
0040 41616161 42626262 00000000 00000000 AaaaBbbb........ 

我們看到xyz都是靜態的文字。 (馬克a,bcconst而不是enum,並且您可能會看到不同的行爲。)因此,雖然enum是編譯時評估的保證,但缺少enum並不妨礙編譯時評估。