Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Recommended style for dynamically sized structs

I need to transfer packets through the internet whose length should be dynamic.

struct packet
{
  int id;
  int filename_len;
  char filename[];
};

The problem is that zero-length arrays are not ISO-compliant.

Should I use char filename[1]; instead? But then sizeof(struct packet) will not return the correct value anymore.

like image 248
codymanix Avatar asked May 26 '09 13:05

codymanix


4 Answers

I think you should look at some existing examples of dynamically sized structures for guidance here. The best example I know of are the TOKEN APIs in Win32. They use the macro ANYSIZE_ARRAY which just resolves down to 1. Raymond Chen did an extensive blog article detailing exactly why they are done this way

  • https://devblogs.microsoft.com/oldnewthing/20040826-00/?p=38043

As for operations such as sizeof failing. This will fail no matter what solution you choose for a dynamically sized struct. sizeof is a compile time operation and you will be re-sizing the structure at runtime. It simply cannot work.

like image 25
JaredPar Avatar answered Nov 10 '22 08:11

JaredPar


I suggest to use char filename[1] and include a terminating 0-byte. This way, you can malloc() the correct structure size and avoid one-off errors like this:

ptr = malloc(sizeof(struct packet)+filename_len);
strncpy(&ptr->filename, filename, filename_len);

But the receiver must to know that it needs to read filename_len+1 bytes.

like image 41
Aaron Digulla Avatar answered Nov 10 '22 07:11

Aaron Digulla


Classic issue. You can simply deal with it (and note that sizeof(foo) may be off by more than one if the compiler rounds the structure size up, which is (I believe) allowed), or you can do something like this:

struct packetheader {
   int id;
   int filename_len;
};
struct packet {
   struct packetheader h;
   char filename[1];
};

This is annoying (you have to use h.id, etc), but it works. Usually I just deal with it being one, but the above might be marginally more portable.

like image 73
jesup Avatar answered Nov 10 '22 06:11

jesup


Indeed zero-length arrays are not part of the standard. But what you have in your code snippet is a flexible array which is part of the ISO C99 standard. If it is possible for you to use C99, I'd use a flexible array, if not jesup's suggestion is probably the best.

like image 26
quinmars Avatar answered Nov 10 '22 07:11

quinmars