Jump to page: 1 2
Thread overview
Minor issue - zero-length fixed size arrays in variable-sized structs..
Re: Minor issue - zero-length fixed size arrays in variable-sized
Jul 08, 2009
bearophile
Jul 09, 2009
Tim Matthews
Jul 09, 2009
Daniel Keep
Jul 09, 2009
Tim Matthews
Jul 10, 2009
Tim Matthews
Mar 29, 2015
Joakim
July 08, 2009
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.
July 08, 2009
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
July 09, 2009
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));
}


July 09, 2009
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);
}
July 09, 2009
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 ^ :)
July 09, 2009
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]; }
>    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);
> }
>

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]).
July 09, 2009
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
July 10, 2009
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
July 10, 2009
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
July 10, 2009
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?
« First   ‹ Prev
1 2