A use case for fromStringz
Andrej Mitrovic
none at none.none
Thu Mar 31 11:25:33 PDT 2011
There are situations where you have to call a C dispatch function, and pass it a void* and a selector. The selector lets you choose what the C function does, for example an enum constant selector `kGetProductName` could ask the C function to fill a null-terminated string at the location of the void* you've passed in.
One way of doing this is to pass the .ptr field of a static or dynamic char array to the C function, letting it fill the array with a null-terminated string.
But here's the problem: If you try to print out that array in D code with e.g. writefln, it will print out the _entire length_ of the array.
This is a problem because the array could quite likely be filled with garbage values after the null terminator. In fact I just had that case when interfacing with C.
to!string can convert a null-terminated C string to a D string, with the length matching the location of the null-terminator. But for char arrays, it won't do any checks for null terminators. It only does this if you explicitly pass it a char*.
So I've come up with a very simple solution:
module fromStringz2;
import std.stdio;
import std.conv;
import std.traits;
import std.string;
enum
{
kGetProductName = 1
}
// imagine this function is defined in a C DLL
extern(C) void cDispatch(void* payload, int selector)
{
if (selector == kGetProductName)
{
char* val = cast(char*)payload;
val[0] = 'a';
val[1] = 'b';
val[2] = 'c';
val[3] = '\0';
}
}
string fromStringz(T)(T value)
{
static if (isArray!T)
{
return to!string(cast(char*)value);
}
else
{
return to!string(value);
}
}
string getNameOld()
{
static char[256] name;
cDispatch(name.ptr, kGetProductName);
return to!string(name);
}
string getNameNew()
{
static char[256] name;
cDispatch(name.ptr, kGetProductName);
return fromStringz(name);
}
void main()
{
assert(getNameOld().length == 256); // values after [3] could quite
// likely be garbage
assert(getNameNew().length == 3);
}
I admit I didn't take Unicode into account, so its far from being perfect or safe.
In any case I think its useful to have such a function, since you generally do not want the part of a C string after the null terminator.
More information about the Digitalmars-d-learn
mailing list