Thread overview
string to char*
Sep 11, 2010
shd
Sep 11, 2010
Simen kjaeraas
Sep 11, 2010
Mariusz Gliwiński
Sep 11, 2010
Andrej Mitrovic
Sep 11, 2010
bearophile
Sep 12, 2010
Jonathan M Davis
Sep 12, 2010
bearophile
Sep 14, 2010
klickverbot
September 11, 2010
Hello,
I'm having a problem in passing a value to char* expecting function
in D 2.0. Already tried:

to!(char*)("my string");

but it seems like there (Phobos) is no template like this. Then,
tried:

cast(char*)to!(char[])("my string")

which looked ok, but i think it's not a proper way to do that. Most strings converted this way works properly, but once:

char* string1 = cast(char*)to!(char[])("my string 1");
char* string2 = cast(char*)to!(char[])("my string 2");

resulted:
string1 = "my string 1"
string2 = "my string 1my string 2"

I can't manage this problem, could You hint me?

September 11, 2010
shd <alienballance@gmail.com> wrote:

> Hello,
> I'm having a problem in passing a value to char* expecting function
> in D 2.0.

Why does the function expect a char*? If it is an external C function,
and it might change the passed values, you should make a duplicate
mutable string, or use char[] in lieu of string.

If it is an external C function that will *not* change the passed
values, and you have write access to the D headers to interface to C,
use const char* instead. If no write access, I would use
cast(char*)myString.ptr.

If it is a D function, why does it not use const? Or for that matter,
why does it not use char[]?

-- 
Simen
September 11, 2010
On 2010-09-11 15:13, Simen kjaeraas wrote:
> Why does the function expect a char*? If it is an external C function,
> and it might change the passed values, you should make a duplicate
> mutable string, or use char[] in lieu of string.
>
> If it is an external C function that will *not* change the passed
> values, and you have write access to the D headers to interface to C,
> use const char* instead. If no write access, I would use
> cast(char*)myString.ptr.

Yes, it's external C function and I can modify bindings (just bindings, not ABI). Now I'll trace back library which is interfacing to me and possibly fix bindings.

You helped me already, thanks a lot. I can already go on (this language is so cool btw.).
September 11, 2010
I'm interfacing with Scintilla (C++), but it works in a different way. It uses messages, which allows it to be linked with practically any language. But I can still pass parameters to be modified by passing the address of the variable instead (the wrapper takes care of that).

Although linking with C++ is difficult, having proper C linkage is a great thing. There's a ton of libraries out there ready to be used right now in D.

2010/9/11 Mariusz Gliwiński <alienballance@gmail.com>:
> On 2010-09-11 15:13, Simen kjaeraas wrote:
>>
>> Why does the function expect a char*? If it is an external C function, and it might change the passed values, you should make a duplicate mutable string, or use char[] in lieu of string.
>>
>> If it is an external C function that will *not* change the passed values, and you have write access to the D headers to interface to C, use const char* instead. If no write access, I would use cast(char*)myString.ptr.
>
> Yes, it's external C function and I can modify bindings (just bindings, not ABI). Now I'll trace back library which is interfacing to me and possibly fix bindings.
>
> You helped me already, thanks a lot. I can already go on (this language is
> so cool btw.).
>
September 11, 2010
shd:
> I'm having a problem in passing a value to char* expecting function
> in D 2.0. Already tried:
> to!(char*)("my string");

A solution, maybe correct:


import std.string: toStringz, indexOf;
import std.c.string: strlen;
import std.stdio: writeln;

void main() {
    string s = "my string";
    assert(indexOf(s, '\0') == -1); // useful
    char* p = cast(char*)toStringz(s);
    writeln(strlen(p));
}


But keep in mind this string p is managed by the D GC.

That cast to cast(char*) is not nice.

There is no need to dup the string given to toStringz because it performs the dup internally (wasting a initialization of 'copy'), this is the cleaned up implementation of toStringz:


const(char)* toStringz(string s) {
    char[] copy = new char[s.length + 1];
    copy[0 .. s.length] = s;
    copy[s.length] = 0;
    return copy.ptr;
}


I don't know why it returns a const(char)* instead of a char*. Do you know why?

Bye,
bearophile
September 12, 2010
On Saturday 11 September 2010 09:07:38 bearophile wrote:
> I don't know why it returns a const(char)* instead of a char*. Do you know
> why?
> 
> Bye,
> bearophile

Well, if you look at toStringz()'s implementation, you may notice that there's commented out code which would not make a copy if there's a 0 in memory one passed the end of the string. It would simply use that 0 as the end of the const char* and avoid the copy. That being the case, it avoids a copy but must be const, because the string is immutable. Now, why that code is commented out, I don't know, and if toStringz() continues to always copy the string, then char* would likely be a better choice. But it could be that whatever issue made it so that the non-copying version was commented out will be fixed at some point, and toStringz() will once again cease to make a copy if it doesn't have to, at which point it would need to return const.

- Jonathan M Davis
September 12, 2010
Jonathan M Davis:
> Well, if you look at toStringz()'s implementation, you may notice that there's commented out code which would not make a copy if there's a 0 in memory one passed the end of the string. It would simply use that 0 as the end of the const char* and avoid the copy. That being the case, it avoids a copy but must be const, because the string is immutable.

I see, thank you for the answer. Generally in the C code that uses the C string I can't be certain that it doesn't modify the string. On the other hand often I need a char* and not a const char*. Ao I'd like toStringz() to always copy and return a char* (Often I need a const pointer to mutable chars).

Another possibility is to have two functions, one that always performs the copy and returns a char*, and one that sometimes doesn't copy and returns a const char*.

Or a single template function that returns a const char* if doconst is true :-)
auto toStringz(bool doconst=false)(string s) { ...

Bye,
bearophile
September 14, 2010
On 9/11/10 3:00 PM, shd wrote:
> Hello,
> I'm having a problem in passing a value to char* expecting function
> in D 2.0. Already tried:
>
> to!(char*)("my string");
>
> but it seems like there (Phobos) is no template like this. Then,
> tried:
>
> cast(char*)to!(char[])("my string")
>
> which looked ok, but i think it's not a proper way to do that. Most
> strings converted this way works properly, but once:
>
> char* string1 = cast(char*)to!(char[])("my string 1");
> char* string2 = cast(char*)to!(char[])("my string 2");
>
> resulted:
> string1 = "my string 1"
> string2 = "my string 1my string 2"
>
> I can't manage this problem, could You hint me?
>

Use std.string.toStringz to convert a D string to a C null-terminated one.

This asymmetry (no to!(char*)(string)) has been discussed once, but I can't remember the reason why it was not implemented right now.