www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Passing string literals to C

reply "Laeeth Isharc" <laeethnospam spammenot_laeeth.com> writes:
What's best practice here?

D strings are not null-terminated.

char* cpling(char *s)
{

So toString("This i
Dec 31 2014
parent reply "Laeeth Isharc" <laeethnospam spammenot_laeeth.com> writes:
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?
Dec 31 2014
next sibling parent Daniel =?UTF-8?B?S296w6Fr?= via Digitalmars-d-learn writes:
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.
Dec 31 2014
prev sibling next sibling parent reply Mike Parker <aldacron gmail.com> writes:
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.
Dec 31 2014
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
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...
Dec 31 2014
parent reply "Meta" <jared771 gmail.com> writes:
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.
Dec 31 2014
parent "Laeeth Isharc" <Laeeth.nospam nospam-laeeth.com> writes:
Thanks for the help.

Laeeth
Dec 31 2014
prev sibling parent "Gary Willoughby" <dev nomad.so> writes:
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).
Jan 01 2015