考虑以下结构和函数
typedef struct __attribute__((__packed__)) req_file {
uint32_t start_pos;
uint32_t byte_count;
uint16_t name_len;
} req_file;
void req_file_hton(req_file *d){
d->name_len = htons(d->name_len);
d->start_pos = htonl(d->start_pos);
d->byte_count = htonl(d->byte_count);
}
void req_file_ntoh(req_file *d){
d->name_len = ntohs(d->name_len);
d->start_pos = ntohl(d->start_pos);
d->byte_count = ntohl(d->byte_count);
}
上面的代码对于许多具有许多字段的结构来说是乏味的。我想配置一次结构的名称和字段,并为我生成函数 struct_name_hton
和 struct_name_ntoh
。我试过玩 x 宏,但运气不好。可移植的 C 预处理器解决方案将受到高度赞赏(不是 C++)。
最佳答案
嗯,这很简单。
#include <stdint.h>
#include <arpa/inet.h>
/* the NETSTRUCT library ------------------------------- */
// for uint32_t
#define NETSTRUCT_dec_uint32_t(n) uint32_t n;
#define NETSTRUCT_hton_uint32_t(n) t->n = htonl(t->n);
#define NETSTRUCT_ntoh_uint32_t(n) t->n = ntohl(t->n);
// for uint16_t
#define NETSTRUCT_dec_uint16_t(n) uint16_t n;
#define NETSTRUCT_hton_uint16_t(n) t->n = htons(t->n);
#define NETSTRUCT_ntoh_uint16_t(n) t->n = ntohs(t->n);
// dec hton ntoh switch
#define NETSTRUCT_dec(type, name) NETSTRUCT_dec_##type(name)
#define NETSTRUCT_hton(type, name) NETSTRUCT_hton_##type(name)
#define NETSTRUCT_ntoh(type, name) NETSTRUCT_ntoh_##type(name)
// calls NETSTRUCT_mod
#define NETSTRUCT1(mod, a) NETSTRUCT_##mod a
#define NETSTRUCT2(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT1(mod, __VA_ARGS__)
#define NETSTRUCT3(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT2(mod, __VA_ARGS__)
#define NETSTRUCT4(mod, a, ...) NETSTRUCT1(mod, a) NETSTRUCT3(mod, __VA_ARGS__)
// TO DO: all up to NETSTRUCT64
// variadic macro overload
#define NETSTRUCT_GET(_1,_2,_3,_4,NAME,...) NAME
// Overlads VA_ARGS with specified mod
#define NETSTRUCT_IN(mod, ...) \
NETSTRUCT_GET(__VA_ARGS__, NETSTRUCT4, NETSTRUCT3, NETSTRUCT2, NETSTRUCT1) \
(mod, __VA_ARGS__)
// entrypoint of out library
#define NETSTRUCT(name, ...) \
\
struct name { \
NETSTRUCT_IN(dec, __VA_ARGS__) \
} __attribute__((__packed__)); \
\
void name##_hton(struct name *t) { \
NETSTRUCT_IN(hton, __VA_ARGS__) \
} \
\
void name##_ntoh(struct name *t) { \
NETSTRUCT_IN(ntoh, __VA_ARGS__) \
}
/* -------------------------------------------------------- */
// adding custom type
#define NETSTRUCT_dec_uint8_t_arr_8(n) uint8_t n[8];
#define NETSTRUCT_hton_uint8_t_arr_8(n) do{}while(0);
#define NETSTRUCT_ntoh_uint8_t_arr_8(n) do{}while(0);
NETSTRUCT(reg_file,
(uint32_t, start_pos),
(uint32_t, byte_count),
(uint16_t, name_len),
(uint8_t_arr_8, example_custom_array)
);
int main() {
struct reg_file t;
reg_file_hton(&t);
reg_file_ntoh(&t);
}
我已经编写了 mactos,所以很容易添加另一个函数,很可能是 void name##serialize(char *in)
和 void name##deserialize(const char *out)
。设计可以稍微重构,以便类型回调 NETSTRUCT_dec_*
接受两个或什至未知数量的 ex 参数。 NETSTRUCT(名称, (type_callback_suffix, (arguments, arguments2)))
。
@edit 添加了自定义数组类型示例和一些行顺序更改。
关于使用宏转换结构中整数字段的字节顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55669848/