string from C function
Jonathan M Davis
newsgroup.d at jmdavisprog.com
Wed May 14 03:36:40 UTC 2025
On Wednesday, May 7, 2025 10:51:27 PM Mountain Daylight Time Andy Valencia via Digitalmars-d-learn wrote:
> On Thursday, 8 May 2025 at 00:53:20 UTC, Mike Parker wrote:
> >> tst44.d(6): Error: cannot implicitly convert expression
> >> `fromStringz(ctime(null))` of type `char[]` to `string`
> > `fromStringz` is giving you a slice of a `char*`, typed
> > `char[]`.
> >
> > `string` is `immutable(char)[]`, so you can't assign `char[]`
> > to it.
> >
> > You could:
> >
> > * change the type of `s` to `char[]`
> > * call `.idup` on the array returned from `fromStringz` to
> > allocate a `string`
> > * use `std.conv.to`
>
> Thank you. I want to work in strings, so the first one's not an
> option. But both the second and third do the trick. Would you
> say the to!string would be the most idiomatic? It worked as
> "to!string(ctime(&t))", but is it safe to assume it's reliably
> dealing with null-terminated strings? It's the pithiest if so.
to!string definitely deals with null-terminated strings, or it wouldn't work
at all. It's not the kind of thing that would work by accident. So, the only
question is whether it allocates a new string or not, since that could
matter depending on what kind of memory the pointer points to (e.g. you
don't want a slice of malloc-ed memory outliving when it would be freed).
If the mutability of the argument was compatible with that of the requested
type (e.g. converting char* to char[] or char* to const(char)[]), then
std.conv.to could just slice the pointer from the start of the string up to
the null character (which is what fromStringz does), so whether you got a
newly allocated array or not would depend on the current implementation, and
relying on it allocating or not arguably wouldn't be wise.
However, what you're doing is converting a char* to string, and you can't
implicitly convert char* to immutable char*, so it's not possible to slice a
char* and get a string in @safe code. This means that if you pass a char*
(or a const(char)*) to to!string, you're guaranteed to get a newly allocated
string.
Now, fromStringz(ptr).idup is guaranteed to allocate even if ptr is
immutable(char)* or immutable(char*), so if there were any concern that you
might ever have an immutable(char)* and wanted to guarantee that you were
going to allocate a new array, then using fromStringz(ptr).idup would be
better, but realistically, you're not going to get immutable(char)* unless
you got a ptr from a string, and those are almost always allocated by D's GC
(in which case, slicing would be fine). You're not going to get anything
that's immutable from C code.
And it could be argued that fromStringz(ptr).idup is more idiomatic, because
it is clearly allocating without having to even think about whether the
implementation could be slicing instead of allocating a copy.
But ultimately, whether you use to!string(ptr) or fromStringz(ptr).idup is
really a matter of personal preference - especially if you're not dealing
with generic code. I suspect that more folks would think that using
to!string(ptr) looked better, but I don't know. Personally, I'd probably use
fromStringz(ptr).idup just to make the operation explicit, but that's simply
my preference. Do whichever you prefer. They both work just fine.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list