On Monday, 24 May 2021 at 16:16:53 UTC, Steven Schveighoffer
wrote:
On 5/24/21 10:02 AM, Mike Parker wrote:
The latest post in the D and C series dives into the weeds of
D and C strings: how they're implemented, when you need to
NUL-terminate your D strings and when you don't, and how the
storage of literals in memory allows you to avoid NUL
termination in one case you might not have considered and
another case that you shouldn't rely on but can in practice
with the current compilers.
There are at least two more posts worth of information to go
into on this topic, but everything in this post is enough to
cover many use cases of D to C string interop.
The blog:
https://dlang.org/blog/2021/05/24/interfacing-d-with-c-strings-part-one/
Reddit:
https://www.reddit.com/r/programming/comments/njyf76/interfacing_d_with_c_strings_part_one/
Nice article!
Note that there is a huge pitfall awaiting you if you use
`toStringz`: garbage collection. You may want to amend the
article to identify this pitfall.
And I'm not talking about requiring `@nogc`, I'm talking about
the GC collecting the data while C is still using it.
In your example:
```d
puts(s1.toStringz());
```
This leaves a GC-collectible allocation in C land. For `puts`,
it's fine, as the data is not used past the call, but in
something else that might keep it somewhere not accessible to
the GC, you'll want to assign that to a variable that lasts as
long as the resource is used.
-Steve
It’s worse than that, no? If the only reference to GC data isn’t
on the stack of a tracked thread, in GC allocated memory or in a
tracked root then it can be freed. Even in D:
void foo(int* a) {
int** b = cast(int**) malloc((int*).sizeof);
*b = a;
a = null;
GC.collect();
**b = 4; // whoops!!
}
foo(new int);
Right? Obviously that collection could be from calling another
function (e.g. a callback from C to D code) or from another
thread. Or am I missing something?