2

Suppose I have the following struct:

typedef struct {
    int mID;
    struct in_addr mIP;
    size_t dataSize;
    // Another structure
    fairness_structure str;
    bool ack;
    bool stability;
    bool stop_message;
}HeaderType;

As you know, the size of a struct would vary due to its alignment. How to fill in the padding between fields with some data, say with zeros?

2 Answers2

7

Just initialize the structure with memset, and the padding will be filled as well.

memset(&mystruct, 0, sizeof(HeaderType));

If you want to really only fill the pads, you can can cast the pointer to char* and do the arithmetics. But in this case you MUST know how the compiler padded the structure, or enforce it yourself with #pragma pack. You can use offsetof() macro to get the offset of struct members.

char *off = (char *)&mystruct + offsetof(HeaderType, ack);
char *pad_start = off + sizeof(mystruct.ack);
char *pad_end   = (char *)&mystruct + offsetof(HeaderType, stability);

Bedtime reading: The Lost Art of C Structure Packing

Marek Vavrusa
  • 246
  • 1
  • 7
  • Thank you, is there anyway to know how the compiler padded the structure? – محمد جعفر نعمة Feb 23 '15 at 16:04
  • It depends. Read the attached link to the article. – Marek Vavrusa Feb 23 '15 at 16:06
  • 1
    It's better to use `sizeof mystruct`, that way you don't risk writing the wrong type name. – unwind Feb 23 '15 at 16:08
  • This is a double edged sword. I've seen a lot of mistakes when an array got later refactored into a pointer, like this: `char mystr[] = "test"; use_it(mystr, sizeof(mystr))` and then `const char *mystr = "test"; use_it(mystr, sizeof(mystr))`. When you're changing a structure, you're likely to change a name, so the compiler will tell you that you should fix your `sizeof()` as well. But it depends on the personal preference, imho I would advise against it. – Marek Vavrusa Feb 23 '15 at 16:09
  • Beware when trying this on _arrays_. Keep in mind (as the link to esr's doc mentions) that an _array_ of structures might have a different _stride_ size; so in addition to the padding between the fields of the structure itself, there may also be padding between one structure and the next. In the case of arrays, neither the _memset_ nor the _offsetof_ trick will work. – Mark Nunberg Feb 23 '15 at 16:34
  • I don't see how this is relevant to the answer. Sure, an array of structs is also padded, but the stride size is the `sizeof(struct)`. You can get the address of the padding the same way, as it will be `[offsetof(last_element) + sizeof(last_element), sizeof(struct)]`. TBH, I took it as a purely academic question, as I fail to see any practical use in seeking alignment holes inside the structures. – Marek Vavrusa Feb 23 '15 at 17:00
2

Controlling the contents of padding bits and bytes does not seem very useful. But if you write the contents of a structure to a file with a single write or fwrite call, You probably care about the padding and may want to make sure they have consistent values, preferably 0, at all times. Not that is matters when you read the contents back from the file, but in order for the file contents to be predictable and reproducible. Some development tools are known to produce unpredictable contents in object or executable files exactly for this reason, making it very difficult to rebuild from source and check signatures.

So if you really need this, you want a simple and portable method.

The bad news is the C Standard does not have a generic solution for this.

The only guaranty about the contents of padding bytes and bits the standard makes is for uninitialized structures of static storage. Padding is guarantied to be zero in this case (in a hosted environment). In practice, this is also true of initialized structures because it is simple enough for compiler writers to do so.

What about local structures with automatic storage? If they are not initialized, both fields and padding contents are indeterminate. If you just clear the bytes with a memset(&s, 0, sizeof(s)) the padding will be cleared and you can start modifying struct members... Bad news again: the C standard describes as Unspecified behaviour The value of padding bytes when storing values in structures or unions (6.2.6.1).

In other words, storing values in structure members can have side effects on the contents of padding bits and bytes. The compiler is allowed to generate code that does that and it may be more efficient to do so.

The method described by Marek beyond the simple memset is very cumbersome to use, especially if you have bitfields. In practice, clearing the structures before you initialize the fields manually seems the simplest way to achieve the purpose, and I have not seen a compilers that takes advantage of the Standard's leniency concerning the padding bytes. If you pass the structures by value, all bets are off as the compiler may generate code that does not copy the padding.

As a conclusion: if you use local structures, clear them with memset before use and do not pass them by value. There is no guaranty padding will keep a 0 value, but that's the best you can do.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • I agree that the method is extremely cumbersome, again I took that as a question as a curiosity not a real use case. In real world, pickling even a packed structures would lead to many other portability issues such as integer endianness. A structure should always be marshalled per-member. – Marek Vavrusa Feb 23 '15 at 19:12