what's the right way to get char* from string?

ZombineDev via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu May 5 23:04:13 PDT 2016


On Thursday, 5 May 2016 at 07:49:46 UTC, aki wrote:
> Hello,
>
> When I need to call C function, often need to
> have char* pointer from string.
>
> "Interfacing to C++" page:
> https://dlang.org/spec/cpp_interface.html
> have following example.
>
> extern (C) int strcmp(char* string1, char* string2);
> import std.string;
> int myDfunction(char[] s)
> {
>     return strcmp(std.string.toStringz(s), "foo");
> }
>
> but this is incorrect because toStringz() returns immutable 
> pointer.
> One way is to write mutable version of toStringz()
>
> char* toStringzMutable(string s) @trusted pure nothrow {
>     auto copy = new char[s.length + 1];
>     copy[0..s.length] = s[];
>     copy[s.length] = 0;
>     return copy.ptr;
> }
>
> But I think this is common needs,
> why it is not provided by Phobos?
> (or tell me if it has)
>
> Thanks,
> aki

In this particular case, if you `import core.stdc.string : 
strcmp`, instead of providing your own extern declaration it 
should work, because in there the signature is correctly typed as 
`in char*` which is essentially the same as `const(char*)` which 
can accept both mutable, const and immutable arguments. Also it 
has the correct attributes so you can call it from `pure`, 
`nothrow` and `@nogc` code.

As others have said, when you do need to convert a string slice 
to a pointer to a null terminated char/wchar/dchar string, 
`toUTFz` can be very useful.

But where possible, you should prefer functions that take an 
explicit length parameter, so you can avoid memory allocation:

```
string s1, s2;
import std.algorithm : min;
import core.stdc.string : strncmp;
strncmp(s1.ptr, s2.ptr, min(s1.length, s2.length));
// (`min` is used to prevent the C function from
// accessing data beyond the smallest
// of the two string slices).
```

Also string slices that point to a **whole** string literal are 
automatically null-terminated:

```
// lit is zero-terminated
string lit = "asdf";
assert (lit.ptr[lit.length] == '\0');
assert (strlen(lit.ptr) == lit.length);
```

However you need to be very careful, because as soon as you make 
a sub-slice, this property disappears:

```
// slice is not zero-terminated.
string slice = lit[0..2];
assert (slice.ptr[length] == 'd');
assert (strlen(slice.ptr) != slice.length);
```

This means that you can't be sure that a string slice is 
zero-termninated unless you can see it in your code that it 
points to a string literal and you're sure that it would never be 
changed to point to something else (like something returned from 
a function).



More information about the Digitalmars-d-learn mailing list