【问题标题】:C Preprocessor macros extension concatenationC 预处理器宏扩展连接
【发布时间】:2016-05-03 13:20:33
【问题描述】:

假设我想使用 C 预处理器来定义一个函数族,其中只有一个参数类型发生变化。我们以带参数的分配函数为例:

#include <stdint.h>
#include <stdio.h>

#define type_vector(t)                                              \
t * t##vector(int32_t nl, int32_t nh)                               \
{                                                                   \
    t * v = NULL; /* malloc(...) */                                 \
    return v;                                                       \
}

type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)

int main() {
    int32_t * p;
    p = int32_tvector(10, 12);
    return 0;
}

这很好用。

现在,假设我想在函数名称中使用较短的类型名称:i8 代替 int8_t,i32 代替 int32_t,等等。 我不想在宏函数声明中添加第二个参数,而是有一个“短”类型名称的定义。 基本上,我写的第一件事是:

#define sn_int8_t   i8
#define sn_int32_t  i32
#define sn_int64_t  i64

#define sn(t)          sn_##t

#define type_vector(t)                                              \
t * sn(t)##vector(int32_t nl, int32_t nh)                           \
{                                                                   \
    t * v = NULL; /* malloc(...) */                                 \
    return v;                                                       \
}

type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)

int main() {
    int32_t * p;
    p = i32vector(10, 12);
    return 0;
}

但是,这不会编译,给出以下错误:

error: pasting ")" and "vector" does not give a valid preprocessing token
 t * sn(t)##vector(int32_t nl, int32_t nh)                           \

据我了解,问题是由于“)”和“#”并排造成的。 所以我做了以下事情:

#define sn_int8_t(f)   i8##f
#define sn_int32_t(f)  i32##f
#define sn_int64_t(f)  i64##f

#define sn2(t,f)       sn_##t(f)

#define type_vector(t)                                              \
t * sn2(t,vector)(int32_t nl, int32_t nh)                           \
{                                                                   \
    t * v = NULL; /* malloc(...) */                                 \
    return v;                                                       \
}

type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)

int main() {
    int32_t * p;
    p = i32vector(10, 12);
    return 0;
}

这又可以正常工作了。

现在,假设我想为函数名称添加前缀,例如“远程_”。

简单地说

#define type_vector(t)                                              \
t * remote_##sn2(t,vector)(int32_t nl, int32_t nh)                  \
{                                                                   \
    t * v = NULL; /* malloc(...) */                                 \
    return v;                                                       \
}

不起作用,因为 sn2 没有展开。所以我尝试了这个:

#include <stdint.h>
#include <stdio.h>

#define sn_int8_t(f)   i8##f
#define sn_int32_t(f)  i32##f
#define sn_int64_t(f)  i64##f

#define sn2(t,f)       sn_##t(f)

#define short_name(n,t,f) n##_##sn2(t,f)

#define remote_type_vector(t)                                       \
t * short_name(remote,t,vector)(int32_t nl, int32_t nh)             \
{                                                                   \
    t * v = NULL;                                                   \
    return v;                                                       \
}

remote_type_vector(int8_t)
remote_type_vector(int32_t)
remote_type_vector(int64_t)

int main() {
    int32_t * p;
    p = remote_i32vector(10, 12);
    return 0;
}

基本上,这不起作用,因为宏 sn2 没有展开,给我这样的声明:

int32_t * remote_sn2(int32_t,vector)

有什么办法吗?

注意:我不想使用 C++ 模板。

【问题讨论】:

  • 有些人声称这种魔法是邪恶的......
  • 使用 灵活的数组成员 会让思考变得更简单。关于其余部分:TL;DR。提供minimal reproducible example
  • “我不想在宏函数声明中添加第二个参数” - 为什么不呢?这并不是说您经常调用宏。第二个参数还允许您使用具有复合名称的类型(char *struct thing)而不使用typedef
  • 如果你不知道,你可以用gcc -E检查预处理器的输出,我想所有的C编译器都有一个选项。
  • @EugeneSh。这种黑暗艺术自史前时期就已被禁止。至少在 18 世纪之前,死灵术、巫术和 C 宏的从业者通常会被逐出教会或被绞死、抽出和四分五裂。

标签: c macros


【解决方案1】:

这是一个可以满足您所有需求的统一解决方案:

#define sn_int8_t(p,s)  p##i8##s
#define sn_int32_t(p,s) p##i32##s
#define sn_int64_t(p,s) p##i64##s

#define sn2(t,p,s)       sn_##t(p,s)

#define type_vector(t)                                              \
t * sn2(t,,vector)(int32_t nl, int32_t nh)                          \
{                                                                   \
    t * v = NULL; /* malloc(...) */                                 \
    return v;                                                       \
}

#define remote_type_vector(t)                                       \
t * sn2(t,remote,vector)(int32_t nl, int32_t nh)                    \
{                                                                   \
    t * v = NULL;                                                   \
    return v;                                                       \
}

type_vector(int8_t)
type_vector(int32_t)
type_vector(int64_t)

remote_type_vector(int8_t)
remote_type_vector(int32_t)
remote_type_vector(int64_t)

【讨论】:

    猜你喜欢
    • 2018-01-04
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 2020-09-18
    • 2014-04-17
    • 1970-01-01
    相关资源
    最近更新 更多