【问题标题】:Obtaining a plain char* from a string in D?从 D 中的字符串中获取普通的 char*?
【发布时间】:2011-06-18 04:03:40
【问题描述】:

我有一个绝对地狱般的时间试图弄清楚如何从 D 字符串 (a immutable(char)[]) 获得一个普通的、可变的 C 字符串 (a char*) 到我可以传递字符数据到遗留 C 代码。 toStringz 不起作用,因为我收到一条错误消息,提示我“无法将 immutable(char)* 类型的表达式 (toStringz(this.fileName())) 隐式转换为 char*”。我是否需要重新创建一个新的、可变的 char 数组并将字符复制过来?

【问题讨论】:

    标签: string d


    【解决方案1】:

    如果您可以更改旧版 C 代码的 D 接口的标头,并且您确定旧版 C 代码不会修改字符串,您可以它接受const(char)*,例如

    char* strncpy(char* dest, const(char)* src, size_t count);
    //                        ^^^^^^^^^^^^
    

    【讨论】:

    • 我真的很困惑为什么你的答案有这么多的赞成票...... OP 没有提到他想要一个 mutable 字符串吗?
    • @Mehrdad,这得到了支持,因为 OP 可能不需要可变字符串。不过,最好包括如何获取可变字符串。
    【解决方案2】:

    是的,它不漂亮,因为结果是不可变的。

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

    解决方案:

    你可以这样做

    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;
    }
    

    这个效率最高,但也是最长的。

    编辑:糟糕,我在if 中有错字;已修复。)

    【讨论】:

    • 最好先执行char[] buffer = (myString.dup ~ '\0') dup 字符串然后追加\0 这样它就不会重新分配两次(一次用于null concat,一次用于dup)跨度>
    • @ratchetfreak:它仍然会重新分配两次。
    • 如果编译器可以优化它,它不会。但char[] buffer = (myString[] ~ '\0');` 只会重新分配一次
    • @ratchet:是的,但你不能依赖编译器来优化它。
    • 这会起作用,但如果接收代码实际上不需要改变任何东西,这不是一个好主意。
    【解决方案3】:

    如果你想将一个可变的char* 传递给一个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 函数。

    如果您知道您正在调用的 C 函数不会更改字符串,那么您可以使用 KennyTM suggests 并更改 C 函数在 D 中的签名以采用const(char)*,或者您可以转换字符串。例如

    auto cstring = toStringz(str);
    cfunc(cast(char*)cstring.ptr);
    

    虽然更改 C 函数的签名会更正确且不易出错。

    听起来我们可能正在修改 std.conv.to 使其足够聪明,以便在转换为 char*const(char)* 等时将字符串转换为以零结尾的字符串。所以,一旦完成,获得一个以零结尾的可变字符串字符串应该更容易,但目前,您几乎只需要复制字符串并将'\0' 附加到它,以便它以零结尾。但无论如何,您永远无法将 string 传递给需要修改它的 C 函数,因为 string 不能被变异。

    【讨论】:

      【解决方案4】:

      如果没有关于您调用哪个函数的任何上下文,很难说什么是正确的解决方案。

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

      分配一个缓冲区:

      auto buffer = new char[](256);  // your own length instead of 256 here
      

      并调用C函数:

      CWriteString(buffer.ptr, buffer.length);
      

      【讨论】:

        【解决方案5】:

        您可以尝试以下方法:

        char a[]="abc";

        char *p=a;

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

        希望它有效。

        【讨论】:

          猜你喜欢
          • 2012-12-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-25
          • 2021-03-08
          • 1970-01-01
          • 1970-01-01
          • 2012-12-07
          相关资源
          最近更新 更多