Thread overview
Calling a C Function with C-style Strings
Nov 30, 2013
Nordlöw
Nov 30, 2013
Dicebot
Nov 30, 2013
Ali Çehreli
Nov 30, 2013
Dicebot
Nov 30, 2013
Adam D. Ruppe
Nov 30, 2013
Dicebot
Nov 30, 2013
Ali Çehreli
November 30, 2013
I'm struggling to call mktemp in D:

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

but I can't figure out how to use it so DMD complains:

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

How do I create a mutable zero-terminated C-style string?

I think I've read somewhere that string literals (`const` or `immutable`) are implicitly convertible to zero (null)-terminated strings.
November 30, 2013
On Saturday, 30 November 2013 at 15:48:28 UTC, Nordlöw wrote:
> I think I've read somewhere that string literals (`const` or `immutable`) are implicitly convertible to zero (null)-terminated strings.

AFAIR, this should work:

char[] name = "alpha".dup;
mktemp(name.ptr);

D literals are zero-terminated so toStringz is only needed if you want to pass to C function slice of literal or some runtime input.

Another option is to declare extern(C) function to take `const (char)*` argument, as far as I remember C it should not affect mangling but will allow to pass literal directly without allocating a mutable copy.
November 30, 2013
On Saturday, 30 November 2013 at 15:48:28 UTC, Nordlöw wrote:
>     /home/per/Work/justd/fs.d(1042): Error: function core.sys.posix.stdlib.mktemp (char*) is not callable using argument types (immutable(char)*)

This is because mktemp needs to write to the string. From mktemp(3):

 The last six characters of template must be  XXXXXX  and  these
 are  replaced  with  a string that makes the filename unique.  Since it
 will be modified, template must not be a string constant, but should be
 declared as a character array.



So what you want to do here is use a char[] instead of a string. I'd go with:


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));
}
November 30, 2013
On Saturday, 30 November 2013 at 15:59:38 UTC, Adam D. Ruppe wrote:
> This is because mktemp needs to write to the string.

Ah disregard my post then, I thought it is yet another C function that misses `const` in signature :)
November 30, 2013
On 11/30/2013 07:59 AM, Adam D. Ruppe wrote:

>      tempBuffer[name.length] = 0; // make sure it is zero terminated
> yourself

Because char.init is not 0 in D: :)

    assert(tempBuffer[name.length + 1] == '\xff');

Ali

November 30, 2013
On 11/30/2013 07:58 AM, Dicebot wrote:

> char[] name = "alpha".dup;
> mktemp(name.ptr);
>
> D literals are zero-terminated so toStringz is only needed if you want
> to pass to C function slice of literal or some runtime input.

However, I doubt that .dup copies that '\0' character. Although the literal has the termination, we are in slice land beyond that literal so the termination must somehow be ensured.

Ali

November 30, 2013
On Saturday, 30 November 2013 at 18:58:30 UTC, Ali Çehreli wrote:
> However, I doubt that .dup copies that '\0' character. Although the literal has the termination, we are in slice land beyond that literal so the termination must somehow be ensured.
>
> Ali

Hm, yes, this also sounds like a valid concern. I thought that for literals \0 is part of actual string but after making a quick check it looks "hidden" behind actual length. So yep, perfectly wrong answer from me :)