www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Minor issue - zero-length fixed size arrays in variable-sized

reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
I noticed in the spec on arrays that "A [fixed-size] array with a
dimension of 0 is allowed, but no space is allocated for it. It's
useful as the last member of a variable length struct.."  This sounds
like C99's "flexible array members," where a struct can have an array
as its last element that isn't given a size, specifically for allowing
variable-sized structs.

Well, the issue with a zero-length fixed-size array is that.. uh, you
can't access anything out of it.  The compiler disallows any indexing
of a zero-length array with constant indices, and at runtime, all
accesses caught by the array bounds checking.  Weirder still, the .ptr
of any zero-length array is always null, so you can't even do things
like "arr.ptr[5] = x;" (which would be perfectly acceptable in my
opinion).

Just a silly issue.
Jul 08 2009
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Jarrett Billingsley:

I have "solved" that problem compiling in release mode...

 I noticed in the spec on arrays that "A [fixed-size] array with a
 dimension of 0 is allowed, but no space is allocated for it.
The future most important implementation of D, LDC, allocates a "bit" for it (I have no idea where this bit goes): http://www.dsource.org/projects/ldc/wiki/Docs#Zero-lengthstaticarrays Bye, bearophile
Jul 08 2009
prev sibling next sibling parent reply Tim Matthews <tim.matthews7 gmail.com> writes:
Jarrett Billingsley wrote:
 I noticed in the spec on arrays that "A [fixed-size] array with a
 dimension of 0 is allowed, but no space is allocated for it. It's
 useful as the last member of a variable length struct.."  .......
It would be interesting if anyone has yet to find this useful. In c it could be used more directly. In D I think its not much use apart from the offset of property. It would be real bad to have to use it like this: import std.stdio; struct S { int a; uint msgSize; char[0] message; } void setMessage(S* s, const char[] msg) { (cast(char*)(s+S.message.offsetof))[0..s.msgSize] = msg[0..s.msgSize]; } char[] getMessage(S* s) { return (cast(char*)(s+S.message.offsetof))[0..s.msgSize]; } S* createS(uint msgSize) { S* s = cast(S*)((new ubyte[S.sizeof+msgSize]).ptr); s.msgSize = msgSize; return s; } void main() { S* s = createS(5); setMessage(s, "hello"); writeln(getMessage(s)); setMessage(s, "world"); writeln(getMessage(s)); }
Jul 08 2009
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
You'd have to be mad to use it like that.

struct S
{
    int a;
    private { size_t size; char[0] data; }
    char[] message() { return data.ptr[0..length]; }
    size_t length() { return size; }

    S* opCall(size_t size)
    {
        return cast(S*)((new ubyte[S.sizeof+size]).ptr);
    }
}

void main()
{
    auto s = S(5);
    s.message[] = "hello";
    writeln(s.message);
    s.message[] = "world";
    writeln(s.message);
}
Jul 08 2009
next sibling parent Tim Matthews <tim.matthews7 gmail.com> writes:
Daniel Keep wrote:
 You'd have to be mad to use it like that.
I am mad.
 
 struct S
 {
     int a;
     private { size_t size; char[0] data; }
     char[] message() { return data.ptr[0..length]; }
     size_t length() { return size; }
 
     S* opCall(size_t size)
     {
         return cast(S*)((new ubyte[S.sizeof+size]).ptr);
     }
 }
 
 void main()
 {
     auto s = S(5);
     s.message[] = "hello";
     writeln(s.message);
     s.message[] = "world";
     writeln(s.message);
 }
I don't know what you'd have to be to use it like that though ^ :)
Jul 08 2009
prev sibling parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Jul 9, 2009 at 2:38 AM, Daniel Keep<daniel.keep.lists gmail.com> wr=
ote:
 You'd have to be mad to use it like that.

 struct S
 {
 =A0 =A0int a;
 =A0 =A0private { size_t size; char[0] data; }
 =A0 =A0char[] message() { return data.ptr[0..length]; }
 =A0 =A0size_t length() { return size; }

 =A0 =A0S* opCall(size_t size)
 =A0 =A0{
 =A0 =A0 =A0 =A0return cast(S*)((new ubyte[S.sizeof+size]).ptr);
 =A0 =A0}
 }

 void main()
 {
 =A0 =A0auto s =3D S(5);
 =A0 =A0s.message[] =3D "hello";
 =A0 =A0writeln(s.message);
 =A0 =A0s.message[] =3D "world";
 =A0 =A0writeln(s.message);
 }
You can't. The rest of my post explains that T[0].ptr is always null, for some reason. Currently I'm doing almost the same thing, though (cast(char*)(this + 1)[0 .. size]).
Jul 09 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 09 Jul 2009 09:47:44 -0400, Jarrett Billingsley  
<jarrett.billingsley gmail.com> wrote:

 On Thu, Jul 9, 2009 at 2:38 AM, Daniel Keep<daniel.keep.lists gmail.com>  
 wrote:
 You'd have to be mad to use it like that.

 struct S
 {
    int a;
    private { size_t size; char[0] data; }
    char[] message() { return data.ptr[0..length]; }
...

 You can't.  The rest of my post explains that T[0].ptr is always null,
 for some reason.

 Currently I'm doing almost the same thing, though (cast(char*)(this +
 1)[0 .. size]).
Would something like this work? (&data)[0..length] -Steve
Jul 09 2009
parent reply Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Jul 9, 2009 at 1:09 PM, Steven Schveighoffer<schveiguy yahoo.com> wrote:

 Would something like this work?

 (&data)[0..length]
Nope; &data is a char[0]*, and slicing it will get you a char[0][]. Which is pretty useless :D
Jul 09 2009
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 09 Jul 2009 20:24:16 -0400, Jarrett Billingsley  
<jarrett.billingsley gmail.com> wrote:

 On Thu, Jul 9, 2009 at 1:09 PM, Steven  
 Schveighoffer<schveiguy yahoo.com> wrote:

 Would something like this work?

 (&data)[0..length]
Nope; &data is a char[0]*, and slicing it will get you a char[0][]. Which is pretty useless :D
d'oh! Yeah, the only improvement I can make on your code then is: (cast(char*)&data)[0..length]; Or the more general: (cast(typeof(data[0])*)&data)[0..length] Which still involves a cast. Crappy. Having the compiler do the right thing is a much better option :) -Steve
Jul 10 2009
parent Tim Matthews <tim.matthews7 gmail.com> writes:
Steven Schveighoffer wrote:
  Having the compiler do the right
 thing is a much better option :)
 
 -Steve
Have you reported this issue as a bug/enhancement?
Jul 10 2009
prev sibling parent "Joakim" <dlang joakim.fea.st> writes:
On Wednesday, 8 July 2009 at 22:55:47 UTC, Jarrett Billingsley 
wrote:
 I noticed in the spec on arrays that "A [fixed-size] array with 
 a
 dimension of 0 is allowed, but no space is allocated for it. 
 It's
 useful as the last member of a variable length struct.."  This 
 sounds
 like C99's "flexible array members," where a struct can have an 
 array
 as its last element that isn't given a size, specifically for 
 allowing
 variable-sized structs.

 Well, the issue with a zero-length fixed-size array is that.. 
 uh, you
 can't access anything out of it.  The compiler disallows any 
 indexing
 of a zero-length array with constant indices, and at runtime, 
 all
 accesses caught by the array bounds checking.  Weirder still, 
 the .ptr
 of any zero-length array is always null, so you can't even do 
 things
 like "arr.ptr[5] = x;" (which would be perfectly acceptable in 
 my
 opinion).

 Just a silly issue.
Just thought I'd mention that this works now, since this is the only forum thread that mentions working with C's flexible array members. You simply define a zero-length array and then access it using .ptr, as in this C binding and example program I recently translated: https://github.com/joakim-noah/usrsctp/blob/master/usrsctp.d#L185 https://github.com/joakim-noah/usrsctp/blob/master/programs/rtcweb.d#L836
Mar 29 2015