2017-08-30 17 views
1

學習d並徹底享受過程,但這段代碼轉換成一個d字符串char*我百思不得其解。我無意中發現它的只是一味的直覺模板是如何工作的,但我想知道它是如何工作轉換d字符串爲char *使用模板

import core.stdc.stdio; 
import core.stdc.string; 
import core.stdc.stdlib; 

extern (C): 

/// Convert a string to a char array 
template charify(const string str, const size_t length) { 
    void charify(char* arr) { 
     foreach(i; 0 .. str.length) { 
      if (i >= length) { 
       break; 
      } 
      arr[i] = str[i]; 
     } 
    } 
} 

int main() { 
    auto k = cast(char*)malloc(4 * char.sizeof); 
    charify!("abcdef", 3)(k); 
    printf("%s %d\n", k, strlen(k)); 
    return 0; 
} 

輸出,我想到的是abc 3,但我真的不知道爲什麼。誰能解釋一下?

+0

如果你沒有意識到,Phobos有一個功能可以做到這一點,稱爲toStringz(並從StringZ走另一條路)。它確實使用了GC,但這也是我的做法。無需模板。 https://github.com/dlang/phobos/blob/master/std/string.d#L243 –

+0

你應該也可以在那裏做一個數組拷貝而不是循環:'arr [0 .. len ] = str [0 .. len];'然後'arr [len] = 0;'終止它。雖然請注意,字符串文字也可以像C字符串一樣工作,所以不需要對它們做任何特殊的處理。 –

回答

1

我不完全知道是什麼困惑在這裏,但我給它一個去。如果我沒有覆蓋某些東西,請隨時提問。 :)

首先,有一個錯誤 - 你得到的字符串並不總是以空值終止。 malloc給出隨機數據,未初始化爲0.您的函數應將最後一個字符設置爲'\0'來解決此問題。

extern(C)行是不必要的 - 你不打算從C中調用charify,尤其是因爲它是一個模板化函數。

在火衛一,在d標準庫,有功能toStringz這確實你的函數應該做的,但使用GC。

不管怎麼說,作爲對你的功能實際上是這樣做的:

template charify(...) { void charify(...){...} }模式被稱爲一個eponymous template。一個相當於更短的簽名將是void charify(const string str, const size_t length)(char* arr)

由於length是一個值類型(不涉及指針),並且D中的字符串是不可變的,因此const在兩個模板參數上都是不必要的。

可以做的其他改進是使用數組操作而不是foreach,將函數的整個主體轉換爲arr[0..min(str.length, length)] = str[];,當然還有空終止。

的清理後的版本將是:

void charify(string str, size_t length)(char* arr) { 
    arr[0..min(str.length, length)] = str[]; 
    arr[length-1] = '\0'; 
} 

在你的情況的模板是不是真的必要 - 一個功能以STR和長度作爲常規參數將是基本上每個方式等同:

void charify(string str, size_t length, char* arr) { 
    arr[0..min(str.length, length)] = str[]; 
    arr[length-1] = '\0'; 
} 

唯一的區別是現在只有一個參數列表,它被調用charify("abcdef", 3, k)。另外,D中的字符串文字始終以空字符結尾,所以可以通過其.ptr property安全地傳遞給C函數。請注意,這只是個案,當你有代碼看起來像printf("%s", "foo".ptr),不printf("%s", functionThatReturnsString().ptr)甚至printf("%s", "foo"[0..1].ptr)。在"foo"[0..1]的情況下,將會打印「foo」,因爲在切片之後沒有插入空終止符。在functionThatReturnsString的情況下,返回的字符串可能會或可能不會以null結尾,如果不是,可能會在最終遇到'\0'之前打印大部分內存。

+0

我使用'-betterC'標誌來避免運行時間,所以不能使用GC。 –