【问题标题】:Is there a way to use the parameter as a prefix in a C macro in GCC有没有办法在 GCC 的 C 宏中使用参数作为前缀
【发布时间】:2019-04-19 11:16:00
【问题描述】:

我正在尝试在 C 中做一些模板的东西: 我需要创建一个带有函数的二维向量结构来处理它们,并且我需要将它们用于 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() 之类的东西时,预处理器会很好地替换名称,但随后不会接受它并出现以下错误:

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));};

【问题讨论】:

  • inline N * N##_new(void)

标签: c macros


【解决方案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 连接成一个单个 令牌。 p>

【讨论】:

  • 哇,好吧,这在我学到的书中没有得到很好的解释。它现在似乎可以很好地预处理/编译(尽管我收到一个关于未定义的对函数 vec2f_new 的引用的链接器错误,你知道为什么吗)?
  • @scippie 关于这本书:也许他们以某种方式将它与#(转换为字符串)预处理器运算符混为一谈,这确实是前缀?关于链接器错误:不幸的是,我不知道,我的主要语言是 C++,我不熟悉 C 中 inline 函数的确切语义(因为这是两种语言显着不同的领域之一)。
  • 谢谢...我通过添加静态关键字解决了这个问题。现在,这些函数被重复添加到每个包含头文件的文件中,作为该文件的唯一函数并内联进行优化。
  • C99 中 inline 本身的语义很难解释,而且几乎不是你想要的。 static inline 更像是 inline 在 C++ 中的行为方式,并且更有意义。
猜你喜欢
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 2015-07-08
  • 1970-01-01
  • 2011-07-24
  • 1970-01-01
相关资源
最近更新 更多