0

I saw next code in the project I work:

struct Str
{
    size_t count;
    T data[1];
};

Str* str = (Str*)malloc(sizeof(Str) + sizeof(T) * count);
str->count = count
...

str->data is used as an array with count elements of T from this point.

Why one would declare T data[1] instead of T* data? Is there any benefit of doing this?

Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211
  • 2
    Read all about it here: http://c-faq.com/struct/structhack.html – StoryTeller - Unslander Monica Nov 26 '13 at 10:01
  • To initialise it with space for one element? However, I really don't like doing that when you're going to change the size later on. – Lord Zsolt Nov 26 '13 at 10:02
  • @LordZsolt, not for changing the size, but for when the size is fixed but known only at run time. I can see why it's popular. – StoryTeller - Unslander Monica Nov 26 '13 at 10:02
  • @RetiredNinja Yes, it's the same questions, but it was very bad formulated there and the answers were not what I expected. – Mircea Ispas Nov 26 '13 at 10:05
  • Yes, I meant it that way. A size calculated at run time will CHANGE the size of the array once, after it's calculated (AKA you'll call malloc). Instead I'd just declare as T* and change the size when the value is calculated. – Lord Zsolt Nov 26 '13 at 10:05
  • nitpick, should be `sizeof(T) * (count - 1)` since sizeof(Str) already includes one T. – john Nov 26 '13 at 10:29
  • @john: In general yes, but in practice T is often 'char' and you get `malloc(sizeof(struct String) + len)`. The "extra" char is used for the null terminator. (And note that in the example given in the question, it's `struct Str`, so it's quite likely that this code *is* from a string type.) – John Bartholomew Nov 26 '13 at 12:17

1 Answers1

2

Your code is not valid C++.

However, it is valid C, sort of. The standard way of writing this in C is to declare the final member as T data[]; (a "flexible-length array"), and the purpose is to allow you do allocate one single dynamic chunk of memory and store both a fixed header and a variable-length array in it together.

There are several limitations to using such a type (e.g. it cannot be the type of an automatic variable, or of an array element). See for example the GCC implementation, which offers several non-standard extensions.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Compiles fine using at least 2 C++ compilers: http://ideone.com/FYkBU9 – Mircea Ispas Nov 26 '13 at 10:09
  • Assuming the type is a POD type is there anything in the C++ standard that makes it invalid C++? – Retired Ninja Nov 26 '13 at 10:09
  • 1
    @RetiredNinja yeah, there is. C++ has no affordance for accessing memory beyond the *declared* subscripts of a fixed array, or the validity of a pointer value beyond one-past the last member. C specifically called out "flexible array member" support in 6.7.2.1-18. No such support exists in C++ that I'm aware of. It may compile. Hell, it may even "work", but not because the language says it will. – WhozCraig Nov 26 '13 at 10:11
  • @WhozCraig Ah, thanks for pointing that out, I thought it might be something like that but couldn't remember exactly. I can't say I've personally used that construct in quite a while, but it isn't terribly uncommon in code I've worked with. It may just be one of those undefined but consistent behaviors with the compilers we use, kinda like the write to one member, read from another union thing. – Retired Ninja Nov 26 '13 at 10:18