Thread overview
Passing string literals to C
Dec 31, 2014
Laeeth Isharc
Dec 31, 2014
Laeeth Isharc
Dec 31, 2014
Daniel Kozák
Dec 31, 2014
Mike Parker
Dec 31, 2014
John Colvin
Dec 31, 2014
Meta
Dec 31, 2014
Laeeth Isharc
Jan 01, 2015
Gary Willoughby
December 31, 2014
What's best practice here?

D strings are not null-terminated.

char* cpling(char *s)
{

So toString("This i
December 31, 2014
Argh - no way to edit.

What's best practice here?

D strings are not null-terminated.
===
cpling.c

char* cpling(char *s)
{
  s[0]='!';
  return s;
}
===
dcaller.d

extern(C) char* cpling(char* s);

void callC()
{
  writefln("%s",fromStringz(cpling("hello\0")));
}

or

void callC()
{
  writefln("%s",fromStringz(cpling(toStringz("hello"))));
}

===

am I missing a better way to do this?
December 31, 2014
V Wed, 31 Dec 2014 11:19:35 +0000
Laeeth Isharc via Digitalmars-d-learn
<digitalmars-d-learn@puremagic.com> napsáno:

> Argh - no way to edit.
> 
> What's best practice here?
> 
> D strings are not null-terminated.
> ===
> cpling.c
> 
> char* cpling(char *s)
> {
>    s[0]='!';
>    return s;
> }
> ===
> dcaller.d
> 
> extern(C) char* cpling(char* s);
> 
> void callC()
> {
>    writefln("%s",fromStringz(cpling("hello\0")));
> }
> 
> or
> 
> void callC()
> {
>    writefln("%s",fromStringz(cpling(toStringz("hello"))));
> }
> 
> ===
> 
> am I missing a better way to do this?

First I am not sure, but you do not need to call fromStringz in this case. Next in this example you even not need to call toStringz, because D string literals are null-terminated. But generally it is better to use toStringz when need pass D strings to C code.

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may go away during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

December 31, 2014
On 12/31/2014 8:19 PM, Laeeth Isharc wrote:
> Argh - no way to edit.
>
> What's best practice here?
>
> D strings are not null-terminated.
> ===
> cpling.c
>
> char* cpling(char *s)
> {
>    s[0]='!';
>    return s;
> }
> ===
> dcaller.d
>
> extern(C) char* cpling(char* s);
>
> void callC()
> {
>    writefln("%s",fromStringz(cpling("hello\0")));
> }
>
> or
>
> void callC()
> {
>    writefln("%s",fromStringz(cpling(toStringz("hello"))));
> }
>
> ===
>
> am I missing a better way to do this?

String literals are always null-terminated. You can typically pass them as-is and D will do the right thing (you can also pass "MyStr".ptr if you want). Use toStringz when the string came from an external source (read from a file, passed into a function and so on), since you can't be sure if it was a literal or not. toStringz will recognize if it has a null-terminator and will not do anything if it does.

Also, you should make sure to consider std.conv.to on any C strings returned into D if you are going to keep them around. fromStringz only creates a slice, which is fine for how you use it here, but could get you into trouble if you aren't careful. std.conv.to will allocate a new string.
December 31, 2014
On Wednesday, 31 December 2014 at 11:45:33 UTC, Mike Parker wrote:
> On 12/31/2014 8:19 PM, Laeeth Isharc wrote:
>> Argh - no way to edit.
>>
>> What's best practice here?
>>
>> D strings are not null-terminated.
>> ===
>> cpling.c
>>
>> char* cpling(char *s)
>> {
>>   s[0]='!';
>>   return s;
>> }
>> ===
>> dcaller.d
>>
>> extern(C) char* cpling(char* s);
>>
>> void callC()
>> {
>>   writefln("%s",fromStringz(cpling("hello\0")));
>> }
>>
>> or
>>
>> void callC()
>> {
>>   writefln("%s",fromStringz(cpling(toStringz("hello"))));
>> }
>>
>> ===
>>
>> am I missing a better way to do this?
>
> String literals are always null-terminated. You can typically pass them as-is and D will do the right thing (you can also pass "MyStr".ptr if you want).

String literals can implicitly convert to const(char)* or immutable(char)*. Neat. It doesn't appear to apply to array literals in general though...
December 31, 2014
On Wednesday, 31 December 2014 at 12:25:45 UTC, John Colvin wrote:
> String literals can implicitly convert to const(char)* or immutable(char)*. Neat. It doesn't appear to apply to array literals in general though...

I believe this is a special case specifically for strings added for convenience when interfacing with C. Walter has said that he is strongly against arrays decaying to points a la C, and D generally does not support it save for this special case.
December 31, 2014
Thanks for the help.

Laeeth
January 01, 2015
On Wednesday, 31 December 2014 at 11:19:36 UTC, Laeeth Isharc wrote:
> Argh - no way to edit.
>
> What's best practice here?
>
> D strings are not null-terminated.
> ===
> cpling.c
>
> char* cpling(char *s)
> {
>   s[0]='!';
>   return s;
> }
> ===
> dcaller.d
>
> extern(C) char* cpling(char* s);
>
> void callC()
> {
>   writefln("%s",fromStringz(cpling("hello\0")));
> }
>
> or
>
> void callC()
> {
>   writefln("%s",fromStringz(cpling(toStringz("hello"))));
> }
>
> ===
>
> am I missing a better way to do this?

To call a C function you can either use string literals which are always null terminated or use std.string.toStringz (when using string variables) to add the null and return a char*.

To convert from char* (from a C function return value) to a D string use std.conv.to!(string).