好吧,这不会赢得环球小姐奖,但我认为它可以满足您的要求:
#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));
}
假设您想要 N=20 个填充字段。您必须PAD_FIELDS(i,
在结构的开头添加 N 个i
,例如从 1 到 20(如我的示例)或从 0 到 19 或任何让您开心的地方。然后,当您需要例如添加的填充时,, 0x80)
这意味着下一个字段将位于距结构开头的偏移量 0x80 处。
运行此代码后,它会输出以下文本:
CPLD_Version offset a0
NID_Version offset 10a2
这个宏的工作方式是用你的字段定义一个结构,然后合并你的字段,并添加根据结构计算的填充。
如果你不介意一些 boost::preprocessor 魔法,这里有一种方法可以让你PAD_FIELDS(1,PAD_FIELDS(2,PAD_FIELDS(3,PAD_FIELDS(4,...
在一开始就自动化整个过程:
#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));
注意用法的变化:
- 在结构的开头,您写入所需的填充元素的数量
CONTAINS_PADDING(n)
在哪里。n
- 在结构结束之前,您必须添加一个“)”。
- 而不是
,0x0A)
指定您必须编写的填充SET_OFFSET(0x0A);
(;
可选)。