我正在尝试从D字符串(immutable(char)[])获取一个普通的、可变的C字符串(char*),以便将字符数据传递给旧的C代码。但是toStringz不起作用,因为我得到一个错误,说我"不能隐式转换表达式(toStringz(this.fileName()))的类型为immutable(char)*到char*"。我需要重新创建一个新的可变char数组并复制字符吗?
如果您可以更改那个遗留C代码的D接口头文件,并且您确定遗留的C代码不会修改字符串,那么您可以使其接受一个const(char)*
,例如:
char* strncpy(char* dest, const(char)* src, size_t count);
// ^^^^^^^^^^^^
是的,这并不美观,因为结果是不可变的。
这就是为什么我总是在我的代码中返回新数组的可变副本。没有必要使它们不可变。
解决方案:
你可以只做以下操作
char[] buffer = (myString ~ '\0').dup; //Concatenate a null terminator, then dup
然后使用buffer.ptr
作为指针。
这样会浪费一个字符串。更好的方法可能是:
char[] buffer = myString.dup;
buffer ~= '\0'; //Hopefully this doesn't reallocate
而后可以使用buffer.ptr
。
另一种解决方案是使用如下方法:
char* toStringz(in char[] s)
{
string result;
if (s.length > 0 && s[$ - 1] == '\0') //Is it null-terminated?
{ result = s.dup; }
else { result = new char[s.length + 1]; result[0 .. s.length][] = s[]; }
return result.ptr;
}
\0
,这样就不会出现两次重新分配内存(一次是为了空串连接,一次是为了复制)。因此,执行char[] buffer = (myString.dup ~ '\0')
会更好。 - ratchet freakchar[] buffer = (myString[] ~ '\0')
只会重新分配一次内存。 - ratchet freakchar*
传递给C函数,你需要分配一个可变的char[]
。因为string
是不可变的(char[]),所以它不起作用。你不能修改不可变变量,所以没有办法将需要改变其元素的string
传递给一个函数(无论是C还是其他语言)。string
,并且你需要将它传递给一个需要char[]
的函数,那么你可以使用to!(char[])
或dup
来获取它的可变副本。另外,如果你想将它传递给C函数,你需要在末尾添加一个'\0'
,使其成为零结尾字符串。最简单的方法是在char[]
上执行~= '\0'
,但更有效的方法可能是这样做:auto cstring = new char[](str.length + 1);
cstring[0 .. str.length] = str[];
cstring[$ - 1] = '\0';
cstring.ptr
传递给你调用的 C 函数。const(char)*
,或者你可以将字符串强制转换。例如:auto cstring = toStringz(str);
cfunc(cast(char*)cstring.ptr);
没有上下文的情况下很难确定正确的解决方案是什么。
通常,如果C函数想要修改或写入字符串,它可能希望您提供缓冲区和长度。通常我会这样做:
分配一个缓冲区:
auto buffer = new char[](256); // your own length instead of 256 here
然后调用C函数:
CWriteString(buffer.ptr, buffer.length);