On Saturday, October 28, 2017 02:46:00 Shriramana Sharma via Digitalmars-d- learn wrote: > On Wednesday, 25 October 2017 at 00:35:29 UTC, Ali Çehreli wrote: > > > char[] name = "/tmp/XXXXXX".dup; > > > > remain valid. The actual issue is the missing '\0'. So, > > > > consider toStringz in this case: > > https://dlang.org/library/std/string/to_stringz.html > > Thanks for your reply, but can you clarify exactly I should use > this? > > char[] name = "/tmp/XXXXXX".toStringz; > > gives > > <src>(13): Error: cannot implicitly convert expression > `toStringz("/tmp/XXXXXX")` of type `immutable(char)*` to `char[]` > > So I tried: > > char[] name = "/tmp/XXXXXX".toStringz.dup; > > which gives > > <src>(13): Error: template object.dup cannot deduce function from > argument types !()(immutable(char)*), candidates are: > /usr/include/dmd/druntime/import/object.d(1943): > object.dup(T : V[K], K, V)(T aa) > /usr/include/dmd/druntime/import/object.d(1979): > object.dup(T : V[K], K, V)(T* aa) > /usr/include/dmd/druntime/import/object.d(3764): > object.dup(T)(T[] a) if (!is(const(T) : T)) > /usr/include/dmd/druntime/import/object.d(3780): > object.dup(T)(const(T)[] a) if (is(const(T) : T)) > > And: > > char[] name = "/tmp/XXXXXX".dup.toStringz; > > gives the error <src>(13): Error: cannot implicitly convert > expression `toStringz(dup("/tmp/XXXXXX"))` of type > `immutable(char)*` to `char[]` > > So I'm not sure what to do?!
Well, for starters, toStringz returns a pointer, not a dynamic array. If you want a dynamic array that's null-terminated, then you'll need to explicitly put a null character on the end unless you're just going to use a string literal (which would mean a string, not a char[], so that won't work here). Also, toStringz specifically returns an immutable(char)* - though looking it over right now, I'd say that that's a bug for the overload that takes const(char)[] instead of string. It really should return const(char)* in that case. But regardless, that means that even changing char[] to char* wouldn't cut it if you're using toStringz, since you're starting with a string. If you want a specific constness, then you can use the more general function, std.utf.toUTFz, which works with multiple character types and differing constness rather than being designed specifically for string like toStringz is. However, something to take into account is that toStringz and toUTFz don't always return the same string (and in fact, they probably never should, because the trick they use to check for the null character one past the end of the string doesn't always work correctly). So, if you're passing a string to a C function that's then going to mutate it, you don't want toStringz or toUTFZ. In that case, it's better to just manually put the null terminator at the end of the string. So, you probably would end up with something like char[] name = "/tmp/XXXXXX\0".dup; auto fd = mkstemp(name.ptr); Then when you return the name, you do something like name[0 .. $ - 1].idup; Alternatively, you could use a static array, but either way, you'd want to put the null terminator in there manually. And fromStringz really isn't necessary, since mkstemp is just going to fill in the array that you gave it, and you know exactly where the null terminator is going to be, since it's just filling in the X's rather than doing something that could end up putting a null terminator anywhere in the array. You can just slice the array to chop off the null terminator, and then dup it or idup if it's a static array (so that you don't return a slice of a local variable), or if it's a dynamic array, then either return it as-is or idup it if you want a string; you could even use std.exception.assumeUnique to just cast it to string if you know that no other references to that data exists (which they wouldn't if you allocated the string inside of the function). Also, you _really_ wouldn't want to use fromStringz if you used a static array, since fromStringz always returns a slice of the original input: inout(char)[] fromStringz(inout(char)* cString) @nogc @system pure nothrow { import core.stdc.string : strlen; return cString ? cString[0 .. strlen(cString)] : null; } But if I were you, I'd just create a char[] with an explicit null terminator, and then afterwards, slice off the null character, and pass it to assumeUnique to get a string, since then you allocate only once and don't have to copy the contents of the array. - Jonathan M Davis