Well, it wonβt win the Miss Universe award, but I think it does what you want:
#include <boost/preprocessor/cat.hpp> typedef unsigned char uchar; typedef unsigned short ushort; #define PAD_FIELDS(i_,f_, n_) \ typedef struct __attribute__((packed)) {f_} ftype##i_; \ typedef struct __attribute__((packed)) {f_ uchar t_;} ttype##i_; \ f_ uchar BOOST_PP_CAT(padding,i_)[n_ - sizeof (BOOST_PP_CAT(ftype,i_)) * (sizeof (BOOST_PP_CAT(ftype,i_)) != sizeof (BOOST_PP_CAT(ttype,i_)))]; struct sFPGA { PAD_FIELDS(1, PAD_FIELDS(2, uchar Spare1[0x24]; ushort DiscreteInput; //CPLD_Version is required to be at offset 0xA0 , 0xA0) // First padding ushort CPLD_Version; uchar more_stuff[0x50]; ushort even_more[4]; //NID_Version is required to be at offset 0x10A2 , 0x10A2) // Second padding ushort NID_Version; } __attribute__((packed)); int main() { printf("CPLD_Version offset %x\n", offsetof(sFPGA,CPLD_Version)); printf("NID_Version offset %x\n", offsetof(sFPGA,NID_Version)); }
Say you want to fill in the fields N = 20. You must add N from these PAD_FIELDS(i, at the beginning of your structure, where i works, for example, from 1 to 20 (as in my example) or from 0 to 19, or from which makes you happy.Then when you need to fill in, add, for example , 0x80) , which means that the next field will be located at offset 0x80 from the beginning of the structure.
After running this code, it displays the following text:
CPLD_Version offset a0 NID_Version offset 10a2
How this macro works, it defines a structure with your fields, then it includes your fields and adds an add-on calculated according to the structure.
If you don't mind boost :: preprocessor magic magic, here you can automate the whole PAD_FIELDS(1,PAD_FIELDS(2,PAD_FIELDS(3,PAD_FIELDS(4,... at the beginning:
#include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/comma.hpp> #include <boost/preprocessor/repetition/repeat.hpp> #include <boost/preprocessor/punctuation/paren.hpp> typedef unsigned char uchar; typedef unsigned short ushort; #define PAD_FIELDS(i_,f_, n_) \ typedef struct __attribute__((packed)) {f_} BOOST_PP_CAT(ftype,i_); \ typedef struct __attribute__((packed)) {f_ uchar t_;} BOOST_PP_CAT(ttype,i_); \ f_ uchar BOOST_PP_CAT(padding,i_)[n_ - sizeof (BOOST_PP_CAT(ftype,i_)) * (sizeof (BOOST_PP_CAT(ftype,i_)) != sizeof (BOOST_PP_CAT(ttype,i_)))]; #define PADMAC(z,n,s) PAD_FIELDS BOOST_PP_LPAREN() n BOOST_PP_COMMA() #define PADREP(n) BOOST_PP_REPEAT(n, PADMAC, junk) #define FORCE_EVAL(...) __VA_ARGS__ #define CONTAINS_PADDING(n) FORCE_EVAL(PADREP(n) #define SET_OFFSET(o) BOOST_PP_COMMA() o BOOST_PP_RPAREN() struct sFPGA { CONTAINS_PADDING(2); uchar Spare1[0x24]; ushort DiscreteInput; //CPLD_Version is required to be at offset 0xA0 SET_OFFSET(0xA0); ushort CPLD_Version; uchar more_stuff[0x50]; ushort even_more[4]; //NID_Version is required to be at offset 0x10A2 SET_OFFSET(0x10A2); ushort NID_Version; ) } __attribute__((packed));
Note what changed when using:
- At the beginning of the structure, you write
CONTAINS_PADDING(n) , where n is the number of desired fill elements. - Right before the end of the structure you must add a ")".
- Instead
,0x0A) to indicate padding, you should write SET_OFFSET(0x0A); ( ; optional).