www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Does D actually support flexible array members?

reply LinguisticMystic <Egor.Sozonov.09 gmail.com> writes:
I'm porting some C code for arena allocator to D, and somehow the 
flexible array members (a feature of C99 for dynamically-sized 
structs) work in D without significant changes in the code. 
Here's my arena definition:

```
struct ArenaChunk {
     size_t size;
     ArenaChunk* next;
     char[] memory; // flexible array member
}

struct Arena {
     ArenaChunk* firstChunk;
     ArenaChunk* currChunk;
     int currInd;
}
```

And here's how I use the FAM's memory for allocating stuff:

```
     void* result = cast(void*)(&ar.currChunk.memory + ar.currInd);
```

This seems to work, but I'm a little doubtful, does D really 
support FAMs in the same way as C, or am I misusing some other D 
feature here? I mean, FAM's aren't even supported by C++, and 
aren't listed on [the D 
reference](https://tour.dlang.org/tour/en/basics/arrays)  yet 
somehow the code works.
Aug 18 2022
next sibling parent reply Krzysztof =?UTF-8?B?SmFqZcWbbmljYQ==?= <krzysztof.jajesnica gmail.com> writes:
No, D does not support flexible array members or dynamically 
sized structs.

`char[]` is a D slice, which is NOT equivalent to a C array.
A slice is basically a pointer+length pair:
```d
// you can't actually name a struct `char[]`, it's just for 
explanation purposes
struct char[] {
     char* ptr; //pointer to first element
     size_t length;
}
```

Also the allocation code probably only worked by accident and 
will likely cause memory corruption:
```d
void* result = cast(void*)(&ar.currChunk.memory + ar.currInd);
```
`&ar.currChunk.memory` doesn't give you a pointer to the first 
slice element - it gives you a pointer to the slice itself (the 
`char[]` "struct"). To get a pointer to the first element you can 
use `ar.currChunk.memory.ptr`, although since the end goal is to 
get a pointer to the `ar.currInd` element it's preferable to 
replace the entire line with this:
```d
void* result = &ar.currChunk.memory[ar.currInd];
```
(this way you get bounds checking on slice indexing so you can't 
get a pointer past the last element of the slice).

Also `void[]` is a more appropriate type for a raw memory array 
than `char[]` (`char[]` in D is used almost exclusively as 
"mutable string", and depending on the implementation the garbage 
collector may not scan `char[]` elements for pointers).
Aug 18 2022
parent LinguisticMystic <Egor.Sozonov.09 gmail.com> writes:
On Thursday, 18 August 2022 at 09:48:48 UTC, Krzysztof Jajeśnica 
wrote:
 ...
Okay, got it, thanks.
Aug 18 2022
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 18 August 2022 at 08:41:02 UTC, LinguisticMystic 
wrote:
 I'm porting some C code for arena allocator to D, and somehow 
 the flexible array members (a feature of C99 for 
 dynamically-sized structs) work in D without significant 
 changes in the code. Here's my arena definition:

 ```
 struct ArenaChunk {
     size_t size;
     ArenaChunk* next;
     char[] memory; // flexible array member
 }

 struct Arena {
     ArenaChunk* firstChunk;
     ArenaChunk* currChunk;
     int currInd;
 }
 ```

 And here's how I use the FAM's memory for allocating stuff:

 ```
     void* result = cast(void*)(&ar.currChunk.memory + 
 ar.currInd);
 ```
I think the closest way to approximate this in D is to use a zero-length static array: ```d struct ArenaChunk { size_t size; ArenaChunk* next; char[0] memory; } ``` Then your usage example becomes ``` void* result = cast(void*)(ar.currChunk.memory.ptr + ar.currInd); ``` Note that in D you must use `.ptr` to get a pointer to the array's first element; it does not decay automatically like in C.
Aug 18 2022
parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 18 August 2022 at 11:25:22 UTC, Paul Backus wrote:
 I think the closest way to approximate this in D is to use a 
 zero-length static array:

 ```d
 struct ArenaChunk {
     size_t size;
     ArenaChunk* next;
     char[0] memory;
 }
 ```
Would Nullable be a good option as well? [https://dlang.org/phobos/std_typecons.html#Nullable](https://dlang.org/phobos/std_typecons.html#Nullable)
Sep 06 2022
parent Paul Backus <snarwin gmail.com> writes:
On Tuesday, 6 September 2022 at 11:51:35 UTC, IchorDev wrote:
 On Thursday, 18 August 2022 at 11:25:22 UTC, Paul Backus wrote:
 I think the closest way to approximate this in D is to use a 
 zero-length static array:

 ```d
 struct ArenaChunk {
     size_t size;
     ArenaChunk* next;
     char[0] memory;
 }
 ```
Would Nullable be a good option as well? [https://dlang.org/phobos/std_typecons.html#Nullable](https://dlang.org/phobos/std_typecons.html#Nullable)
For a dynamically-sized struct? No, it would not; Nullable has a fixed size.
Sep 06 2022