This seems like a bad idea, but you can accomplish it by abusing a union and anonymous structure members:
#define SET_FIELD(Type, Name, Offset) \
struct { unsigned char Padding##Offset[Offset]; Type Name; }
#pragma pack(push, 1)
typedef union
{
SET_FIELD(unsigned int, field1, 15);
SET_FIELD(unsigned int, field2, 64);
SET_FIELD(unsigned int, field3, 93);
} ManualStructure;
#pragma pack(pop)
#include <stddef.h>
#include <stdio.h>
int main(void)
{
printf("field1 is at offset %zu.\n", offsetof(ManualStructure, field1));
printf("field2 is at offset %zu.\n", offsetof(ManualStructure, field2));
printf("field3 is at offset %zu.\n", offsetof(ManualStructure, field3));
}
The output of the above is:
field1 is at offset 15.
field2 is at offset 64.
field3 is at offset 93.
The fact that the array used for padding is named Padding##Offset
will also alert you to erroneous uses of the same offset, since that will result in two members with the same name. However, it will not warn you of partial overlaps.
You can also do it with GCC and Clang’s attribute feature instead of a #pragma
:
#define SET_FIELD(Type, Name, Offset) \
struct __attribute__((__packed__)) { unsigned char Padding##Offset[Offset]; Type Name; }
typedef union
{
SET_FIELD(unsigned int, field1, 15);
SET_FIELD(unsigned int, field2, 64);
SET_FIELD(unsigned int, field3, 93);
} ManualStructure;
A problem is that writing to any member of a union is allowed by the C standard to affect bytes that do not correspond to that member but that do correspond to others. For example, given ManualStructure x
, the assignment x.field1 = 3;
is allowed to alter the bytes of x.field3
, since those bytes do not correspond to the bytes of the structure that contains x.field1
. You might workaround this by including an additional member in each anonymous structure that pads its bytes out to the full length of the ManualStructure
. Then, whenever you write to a field, you are writing to a member whose bytes occupy the entire union, so there are none that do not correspond to that member. However, to do this, you would have to know the total size of the structure in advance or at least be able to select some bound for it.