String 从D中的字符串获取普通字符*?

String 从D中的字符串获取普通字符*?,string,d,String,D,我花了很长时间试图弄清楚如何从一个D字符串(一个不可变的(char)[])中获得一个简单的、可变的C字符串(一个char*),以便将字符数据传递给遗留的C代码。ToString gz不起作用,因为我收到一个错误,它说我“无法将immutable(char)*类型的表达式(toString gz(this.fileName())隐式转换为char*”。我是否需要重新创建一个新的、可变的字符数组并复制这些字符?是的,这并不漂亮,因为结果是不可变的 这就是为什么我总是在代码中返回新数组的可变副本的原因

我花了很长时间试图弄清楚如何从一个D字符串(一个不可变的(char)[])中获得一个简单的、可变的C字符串(一个char*),以便将字符数据传递给遗留的C代码。ToString gz不起作用,因为我收到一个错误,它说我“无法将immutable(char)*类型的表达式(toString gz(this.fileName())隐式转换为char*”。我是否需要重新创建一个新的、可变的字符数组并复制这些字符?

是的,这并不漂亮,因为结果是不可变的

这就是为什么我总是在代码中返回新数组的可变副本的原因。让它们不变是没有意义的

解决方案:

你可以这么做

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;
}
这是最有效的,也是最长的


Edit:哎呀,我在
if
中有一个打字错误;已修复。)

您可以尝试以下操作:

字符a[]=“abc”

char*p=a

现在可以在任何函数中将指针“p”传递给数组


希望它能工作。

如果您可以更改该遗留C代码的D接口头,并且您确定遗留C代码不会修改字符串,您可以让它接受一个
常量(char)*
,例如

char*strncpy(char*dest,const(char)*src,size\u t count);
//                        ^^^^^^^^^^^^

如果没有调用函数的上下文,很难说什么是正确的解决方案

通常,如果C函数想要修改或写入字符串,它可能希望您提供缓冲区和长度。通常我做的是:

分配缓冲区:

auto buffer = new char[](256);  // your own length instead of 256 here
并调用C函数:

CWriteString(buffer.ptr, buffer.length);

如果要将可变
char*
传递给C函数,则需要分配可变
char[]
<代码>字符串不起作用,因为它是不可变的(char)[]。您无法更改不可变变量,因此无法将
字符串
传递给需要更改其元素的函数(C或其他)

因此,如果您有一个
字符串
,并且需要将其传递给一个接受
char[]
的函数,那么您可以使用
来!(char[])
dup
并获取它的可变副本。此外,如果要将其传递给C函数,则需要在其上附加一个
'\0'
,使其以零结尾。最简单的方法是在
char[]
上执行
~='\0'
,但更有效的方法可能是执行以下操作:

auto cstring = new char[](str.length + 1);
cstring[0 .. str.length] = str[];
cstring[$ - 1] = '\0';
在这两种情况下,您都将cstring.ptr传递给正在调用的C函数

如果您知道您正在调用的C函数不会改变字符串,那么您可以执行as并改变C函数在D中的签名,以获取一个
const(char)*
,也可以强制转换字符串。e、 g

auto cstring = toStringz(str);
cfunc(cast(char*)cstring.ptr);
不过,更改C函数的签名会更正确,也更不容易出错


听起来我们可能正在将
std.conv.to
更改为
char*
const(char)*
,等等。因此,一旦完成,获得一个以零结尾的可变字符串应该会更容易,但目前,您几乎只需要复制字符串并在其上附加一个
'\0'
,使其以零结尾。但是不管怎样,你永远无法将
字符串
传递给需要修改它的C函数,因为
字符串
是不能变异的。

最好先做
char[]buffer=(myString.dup~'\0')
复制字符串,然后追加
\0
,这样就不会重复两次了(一次用于空concat,一次用于dup)@ratchetfreak:它仍然会realloc两次。如果编译器可以优化它,它不会。但是
char[]buffer=(myString[]~'\0')
;`will only realloconce@ratchet:是的,但你不能依赖编译器来优化它。这会起作用,但如果接收代码实际上不需要任何变异,这不是一个好主意。我真的很困惑为什么你的答案有这么多的向上投票……OP没有提到他想要一个可变字符串吗?@Mehrdad,这已经得到了你的支持pvotes,因为OP可能不需要可变字符串。不过,最好包括如何获取可变字符串。