1

I have following struct:

struct SkipListNode{ void *data; // 8 bytes uint8_t size; // 1 byte // 7 bytes padding here... void *next[1]; // dynamic array, 8 bytes each "cell" }; 

I am using malloc() and I am allocating more space than sizeof(SkipListNode), so I am extending the next[] array.

I want to avoid 7 bytes waste. I can completely remove size field, but then I should keep single NULL (8 bytes) at the end of the array. However this does not help reducing the size.

Shall I use __ attribute__((__ packed__)) or there some different way I could do the trick?

This must be compiled under C and C++ as well.

Compiler is gcc.

15
  • 2
    have you considered #pragma pack(1) Commented Jun 23, 2015 at 7:12
  • 1
    Just to make sure,Compiler directive for packing structure is different for different compilers.Please specify the compiler as well in question. Commented Jun 23, 2015 at 7:12
  • 1
    @Nick that's correct, but I'd give the OS some credit for managing it's own resources. When you use packed, the actual size if the smallest size possible for this structure. I believe the extra padding in the malloc level does not go to waste (think of the consequences of that!), but rather being reused for further malloc calls. Anyhow its easy to test... just run your process with 1000 structs and look at how much memory it consumes. Better do that before you write your own allocator Commented Jun 23, 2015 at 7:31
  • 3
    @Ishay: the memory in the unpacked struct goes to waste. It is added so that the variables sit on 'even' boundaries in regard to the machine word (usually 64bits nowadays). If you pack this, which is usually used for transmitting across machine boundaries, since only then the real structure is known, the vars sit tightly one after another. Which means, when you load them, there will be (afaik) additional operations to sort that out. So be aware you are trading memory for CPU. Packing should only be done when it is really,really, really, necessary. Commented Jun 23, 2015 at 7:40
  • 1
    @Lundin: no it is not support flexible members, this is why size is 1 instead of 0 or just []. But code works perfectly OK, you need just to remember this 1 when allocating. This works even with POD classes Commented Jun 23, 2015 at 9:46

2 Answers 2

3
#include <stdio.h> #include <stdint.h> struct SkipListNode{ void *data; // 8 bytes uint8_t size; // 1 byte void *next[1]; }; struct SkipListNode_pack{ void *data; // 8 bytes uint8_t size; // 1 byte void *next[1]; } __attribute__((packed)); int main(int argc, char** argv) { printf("%d:%d\n", sizeof(struct SkipListNode), sizeof(struct SkipListNode_pack)); return 0; } 

The output from the above code:
ishaypeled@arania sandbox]$ ./test
24:17

So yeah, you should definitely use __attribute__((packed)) in your case if you want to save memory. On the other hand, like @MarioTheSpoon states - it may come with a performance penalty.

I'd check the padding solution to see if you can live with that penalty on your specific machines. My bet is you won't even notice it unless you're really performance critical.

Sign up to request clarification or add additional context in comments.

4 Comments

I disagree! Only use #pragma pack(1) when it is really necessary. Wasting ~100k in a standard programm on a standard computer should not be the most of the worries. Of course, if it is some kind of embedded system or you are allocating millions of these records, the reasoning may be different. The system tricks you again, since malloc will again align the buffers on 64bit boundaries (on the described system).
Is there any particular reason why you ommited the next member as per the OP's struct?
@MarioTheSpoon The motivation for this question was to save memory... I already agreed it may cause CPU tradeoff, but that's really what the author requested...
There's an interesting discussion about the CPU penalty here: stackoverflow.com/questions/3454673/…
0

I accepted the other answer,

however, I did considered refactoring of the program, I found a way to proceed correctly, without knowing the size of the array.

If anyone is interested here it is:
https://github.com/nmmmnu/HM3/blob/master/skiplist.cc

So I eliminated the size field and I eliminated the end NULL. Now the struct is aligned :)

While refactor, I remember that one may use malloc_usable_size() to find the size of allocated block. This is heavy non-portable hack, but could work well at some other cases.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.