有没有一种方法可以将参数用作GCC中C宏的前缀

时间:2019-04-19 11:16:01

标签: c macros

我正在尝试在C中做一些模板工作: 我需要创建一个带有函数的2d向量结构,以便与它们一起工作,并且需要将它们用于类型int,unsigned int,float,double和甚至其他都支持基本数学功能的类型。

我可以为每种类型编写所有代码。如果我在其中之一中编写了一个错误,则可能会忘记在所有其他错误中进行修复。我以前在C ++中做到了,而我只是使用模板,但是现在我想要在C(C11)中……没有。

所以我看一下宏的内容,我发现可以使用##标记从字面上使用宏的传递参数。

这是我尝试的一些代码:

#define DECLARE_VEC2(N, T) \
  typedef struct { T x, y;} N; \
  inline N *##N_new() { return malloc(sizeof(N));}

DECLARE_VEC2(vec2i, int);
DECLARE_VEC2(vec2f, float);
DECLARE_VEC2(vec2d, double);

它不起作用。 ## N不会被vec2i / vec2f / vec2d取代,而只会保留## N甚至只是N。编译器不会接受它,并且当我在文件上运行带有-E标志的gcc时,我看到了预处理器确实不能取代它。

但是,如果我在## N和_new之间添加了一个空格,则预处理器会替换它,但是该空格也存在,显然在编译时会出现问题。

但是,如果我将函数名称更改为new _ ## N,则它不仅可以进行预处理,而且可以正常工作。

但是我不想要垃圾! 我以这种方式创建所有具有功能的结构:typename_function(),并且由于这个愚蠢的问题而不想更改它。

所以,问题是:有办法解决这个问题吗?

注意:我也尝试过类似的操作,例如向包含下划线的宏添加一个额外的参数,或者甚至在添加下划线的宏中声明一个宏,但它们都遇到了相同的问题:需要某种分隔符使预处理器了解名称在下划线之前或下划线之前结束。

编辑:奇怪的是,当使用## N ## _ new()之类的东西时,预处理器将名称替换为fine,但是随后不会接受诸如以下错误的消息:

error: pasting "*" and "vec2i" does not give a valid preprocessing token
   inline N * ##N##_new() { return malloc(sizeof(N));}

尽管生成的代码似乎是正确的(gcc -E):

typedef struct { int x, y;} vec2i; inline vec2i *vec2i_new() { return malloc(sizeof(vec2i));};

1 个答案:

答案 0 :(得分:1)

##不是前缀运算符,它是一个中缀运算符—与+类似的二进制连接运算符。因此,您将像这样使用它:

#define DECLARE_VEC2(N, T) \
  typedef struct { T x, y;} N; \
  inline N * N##_new() { return malloc(sizeof(N));}

请注意,##周围的空格将被忽略,因此,如果您认为它更具可读性,也可以这样做以达到相同的效果:

#define DECLARE_VEC2(N, T) \
  typedef struct { T x, y;} N; \
  inline N * N ## _new() { return malloc(sizeof(N));}

这也应该解释为什么会出现错误“未提供有效的预处理令牌”的问题:您实际上是在尝试将*int连接成一个 single 令牌。