6

我正在努力打电话给mktempD:

import core.sys.posix.stdlib;
import std.string: toStringz;
auto name = "alpha";
auto tmp = mktemp(name.toStringz);

但我不知道如何使用它,所以 DMD 抱怨:

/home/per/Work/justd/fs.d(1042): Error: function core.sys.posix.stdlib.mktemp (char*) is not callable using argument types (immutable(char)*)

如何创建可变的以零结尾的 C 样式字符串?

我想我在某处读过字符串文字 (constimmutable) 可以隐式转换为零 (null) 终止的字符串。

4

2 回答 2

8

对于这个特定的问题:

这是因为 mktemp 需要写入字符串。从 mktemp(3) 开始:

模板的最后六个字符必须是 XXXXXX,并且这些字符被替换为使文件名唯一的字符串。由于会被修改,模板不能是字符串常量,而应该声明为字符数组。

因此,您在这里要做的是使用 char[] 而不是字符串。我会去:

import std.stdio;

void main() {
    import core.sys.posix.stdlib;

    // we'll use a little mutable buffer defined right here
    char[255] tempBuffer;
    string name = "alphaXXXXXX"; // last six X's are required by mktemp
    tempBuffer[0 .. name.length] = name[]; // copy the name into the mutable buffer
    tempBuffer[name.length] = 0; // make sure it is zero terminated yourself

    auto tmp = mktemp(tempBuffer.ptr);
    import std.conv;
    writeln(to!string(tmp));
}

通常,可以通过以下两种方式之一来创建可变字符串:一种是 .dup 某些东西,另一种是像我上面所做的那样使用堆栈缓冲区。

toStringz不关心输入数据是否可变,它总是返回不可变的(显然......)。但是自己做很容易:

auto c_str = ("foo".dup ~ "\0").ptr;

这就是你的做法, .dup 制作一个可变副本,并自己附加零终止符以确保它在那里。

string name = "alphaXXXXXX"; // last six X's are required by mktemp
auto tmp = mktemp((name.dup ~ "\0").ptr);
于 2013-11-30T16:05:11.057 回答
8

除了Adam's great answer之外,还有std.utf.toUTFz,在这种情况下你可以这样做

void main()
{
    import core.sys.posix.stdlib;
    import std.conv, std.stdio, std.utf;

    auto name = toUTFz!(char*)("alphaXXXXXX");
    auto tmp = mktemp(name);
    writeln(to!string(tmp));
}

std.utf.toUTFzstd.string.toStringz更强大的表亲,因为它将生成以空字符结尾的 UTF-8、UTF-16 和 UTF-32 字符串(而不仅仅是 UTF-8)以及任何级别的 constness。不利的一面是,对于您只需要的情况,它更加冗长immutable(char)*,因为您必须指定返回类型。

但是,如果效率是一个问题,Adam 的解决方案可能会更好,因为它避免了mktemp在堆上分配您传递给的 C 字符串。toUTFz虽然更短,所以如果你不关心在堆上分配 C 字符串的效率成本(大多数程序可能不会),那么toUTFz可以说更好。这取决于您的特定程序的要求。

于 2013-11-30T20:49:59.340 回答