【问题标题】:Indirect preprocessor substitution C间接预处理器替换 C
【发布时间】:2014-01-16 23:30:33
【问题描述】:

有没有一种方法可以让宏使用传递给它的定义值,而不是定义文本本身?

这是一个奇怪的例子,我预计预处理器可以实现。

一个名为test.cC 文件,其中包含两次以定义从main 调用的两个不同函数。

#ifndef IS_INDIRECT
#define IS_INDIRECT

/* int */
#define NUMTYPE int
#define PREFIX int_

#include "test.c"

#undef NUMTYPE
#undef PREFIX

/* short */
#define NUMTYPE float
#define PREFIX float_

#include "test.c"

#undef NUMTYPE
#undef PREFIX

#include <stdio.h>

int main(int argc, const char **argv)
{
    printf("test int %d\n", int_squared(4));
    printf("test float %f\n", float_squared(2.5));

    return 0;
}

#else

/* function body */

#define fn(prefix, id) prefix ## id

NUMTYPE fn(PREFIX, squared)(NUMTYPE val)
{
    return val * val;
}

#endif

给出以下错误:

In file included from test.c:18:0:
test.c:37:12: error: conflicting types for 'PREFIXsquared'
 NUMTYPE fn(PREFIX, squared)(NUMTYPE val)
            ^
test.c:35:24: note: in definition of macro 'fn'
 #define fn(prefix, id) prefix ## id
                        ^
In file included from test.c:9:0:
test.c:37:12: note: previous definition of 'PREFIXsquared' was here
 NUMTYPE fn(PREFIX, squared)(NUMTYPE val)
            ^
test.c:35:24: note: in definition of macro 'fn'
 #define fn(prefix, id) prefix ## id

我想让宏扩展 PREFIX 到它定义的值,所以我得到 int_squared 而不是 PREFIXsquared

【问题讨论】:

    标签: c c-preprocessor


    【解决方案1】:

    是不是你要找的东西?

    #define xxx(x,y)   x##y
    #define CONCAT(x, y)  xxx(x, y)
    
    
    #define function(type, operation, prm) type CONCAT(operation, type) (type prm)
    
    function (int, square_, value) // int square_int (int value)
    {
        return value * value;
    }
    

    ## 的间接使用允许定义一个使用连接的宏(在我们的示例中为function)。当宏被定义时,CONCAT 扩展为 xxx
    并在宏被调用时解析为x##y

    编辑:感谢各种贡献者:

    • ## 被称为标记粘贴操作符,有时也称为标记连接操作符
    • C/C++预处理器更详细的解释arguments prescan
    • interesting blog article 关于该主题
    • 如果您仔细研究由 ISO 人员添加的令人难以置信的模糊和任意保留标识符列表(您必须咳嗽 about $200 才能获得真正的规范,或者求助于 second hand information,或者询问您最喜欢的大师),你最终会注意到它包括那些以一个下划线开头的,也有两个或更多的,所以我的“_CONCAT”变成了“xxx”。

    坦率地说,他们把 C 语言弄得一团糟,以至于我再也不敢在专业环境中使用该语言了。我很高兴我的 IT 时代结束了。

    【讨论】:

    • 太好了,这行得通,如果我想了解预处理器的这种特定用法,是否有一些与需要宏调用宏的情况相关的常用术语?跨度>
    • 我真的不知道这个技巧背后的理论。当我第一次偶然发现这个问题时,互联网对程序员并不那么友好(至少从法国看到),所以我不得不自己解决。但是 K&R 是一部杰作,如果你仔细阅读它,答案就在那里:)。我找到了this quite thorough and interesting article on the subject,虽然它似乎也不依赖于特定的理论。
    • 这个工作的原因是有一个处理扩展的预扫描 - 但没有第二个预扫描。这样如果有对宏的嵌套调用,事情就会起作用。我怀疑这只是……利用它:)。你可以在这里阅读更多相关信息:gcc.gnu.org/onlinedocs/cpp/…
    • 仅供参考,## 被称为令牌粘贴运算符,有时也称为令牌串联运算符。
    • 请注意_CONCAT 是reserved identifier,因此应注意使用
    【解决方案2】:

    您也可以使用X-Macros 执行此操作:

    funcs_x.h

    /* N.B. no guard macro */
    FUNC(int)
    FUNC(float)
    

    ma​​in.c

    #define FUNC(x_) static x_ x_ ## _squared ( x_ val ) { return val * val; }
    #include "funcs_x.h"
    #undef FUNC
    
    
    int main(int argc, const char **argv) { ... }
    

    这似乎是你想要做的。

    【讨论】:

      猜你喜欢
      • 2014-07-30
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-21
      • 2021-12-08
      • 1970-01-01
      相关资源
      最近更新 更多