Disallow arrays as pointers
bearophile
bearophileHUGS at lycos.com
Tue Nov 1 17:30:05 PDT 2011
In the meantime Walter has added the patch to the latest DMD.
Timon Gehr:
> That works without the cast.
> That works without the ".ptr".
Right. There is an implict conversion between the 2-word struct of the string to the nude pointer.
> I was casting to char*, not const(char*). It is just that occasionally C
> headers/bindings lack the const qualifier. Then passing a string literal
> is achieved simplest by a cast to char*.
In some situations like that I think that using someString.dup.ptr looks safer, or better using toStringz:
http://d-programming-language.org/cutting-edge/phobos/std_string.html#toStringz
I'd like toStringz to be pure and return a char*, so its result is assignable to immutable despite being fit for C functions without const too.
To do this, it can't contain a ~ (string concat) because currently the ~ is not a pure function, it always returns a string, dstring, wstring. So I think this should compile:
char[] foo(string s1, string s2) pure {
return s1 ~ s2;
}
void main() {}
And regarding toStringz(), this modified version seems to work as desired:
import core.stdc.string;
char* toStringz(immutable(char[]) s) pure nothrow
in
{
// The assert below contradicts the unittests!
//assert(memchr(s.ptr, 0, s.length) == null,
//text(s.length, ": `", s, "'"));
}
out (result)
{
if (result)
{
auto slen = s.length;
while (slen > 0 && s[slen-1] == 0) --slen;
assert(strlen(result) == slen);
assert(memcmp(result, s.ptr, slen) == 0); // overkill?
}
}
body
{
/+ Unfortunately, this isn't reliable.
We could make this work if string literals are put
in read-only memory and we test if s[] is pointing into
that.
/* Peek past end of s[], if it's 0, no conversion necessary.
* Note that the compiler will put a 0 past the end of static
* strings, and the storage allocator will put a 0 past the end
* of newly allocated char[]'s.
*/
char* p = &s[0] + s.length;
if (*p == 0)
return s;
+/
// Need to make a copy
auto copy = new char[s.length + 1];
copy[0..s.length] = s;
copy[s.length] = 0;
return copy.ptr;
}
void main() {
string t = "hello";
char* s1 = toStringz(t);
const(char*) s2 = toStringz(t);
immutable(char*) s3 = toStringz(t);
immutable(char)* s4 = toStringz(t);
}
> I don't think we really need that feature, I just think that removing it breaks
> existing code without a reason.
>
> extern(C) void puts(char* str);
> void main() {
> puts(cast(char*)"hello");
> }
I prefer something like:
extern(C) void puts(char* str);
void main() {
puts(Deconst!("hello".ptr));
}
This avoids a cast, a Deconst template doesn't change the data, it never forces the string to be of a specific char type.
Thank you for your answers,
bearophile
More information about the Digitalmars-d
mailing list