使用宏转换结构中整数字段的字节顺序

标签 c metaprogramming preprocessor x-macros

考虑以下结构和函数

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_htonstruct_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/

相关文章:

c - Flex 和 Bison,检测宏语句(新手)

c - 后缀计算器不起作用,为什么? - C

php - Javascript 动态变量名

xcode4 - XCode 的项目设置中忽略了预处理器宏,但目标设置中没有忽略

Drupal主题预处理功能-初级链接

c - 中位数的中位数不能正常工作

C程序不打印

C++ meta-splat 函数

Groovy 扩展元类

java - 使用 Javacc/push 预处理流中的一些字符?