... you seem to have missed that I inherited the project with the alignment bug.
A bug is always a consequence of a programmer's mistake. Someone years ago hired an incompetent programmer and he made a bug. You woudn't say that the bad hiring decision is somehow related
to the alignment, would you?
That is a very big IF. What if your input buffer gets misaligned because someone changes a pointer somewhere or inserts an extra field?
This is a very good question. If you use a structure in communications then your structure may change in the future. Therefore, you design it in such a way that the communicating parties have means to figure out what version of the structure they get. At the very least you include the length field in the end, and you make sure your structure is easy to align by placing padding or reserved fields at the end. Such measures ensure that any number of programmers can use your communication protocol and it works well across the versions and platforms.
If one of the thousands of programmers who use your protocol won't take time to understand the mechanism and misaligns something or otherwise fails to follow the protocol, this is clearly a bug. You don't want to make 999 good programmers write extra parsing code just because one programmer is incompetent, right?
I think this thread has deviated from the original question which the IP has posted. The OP didn't ask about communications. He asked about whether it's a good idea to use bitfields (combining multiple individual variables into a single integer) or it's better to use separate variables.
I personally do not use bitfields, I prefer bitwise logic and masks. Such approach appears more flexible to me, but, under the hood, it's the same as a bitfields.
If variables are 1-bit long (TRUE or FALSE) then it's a good idea to unite them into a single number. Many CPUs will have some sort of instructions to access single bits. More importantly, you can access several variables together. Such as you can test if any one of flag_a, flag_d or dlag_e in a single operation. If these were different variables, it wouldn't be so easy. Similarly, you can set multiple flags by or'ing, clear them by and'ing etc. Also, you can pass the whole set of flags to a function as a single parameter.
For 2-3-bit long variables, the access to a bitfield becomes inefficient. To set the bitfield, you need to read the variable, "and" it with the mask, "xor" it with the value, then write back. Some of the CPUs can combine "and" and "xor" in s single instruction (and even do a shift), but there's still a need to read, modify, and write. Single variable requires only a write, which definitely beats the bitfield.
Of course, 8-bit bitfield is as good as a separate variable.