2017-08-30 15 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。 –