【问题标题】:CPP: avoiding macro expansion of a macro function parameterCPP:避免宏函数参数的宏扩展
【发布时间】:2010-12-25 05:59:23
【问题描述】:

我想做的(用于记录目的)是这样的:

编写此代码是为了说明我的问题,实际代码很复杂,是的,即使在 C++ 上我也有充分的理由使用宏 =)

# define LIB_SOME 1
# define LIB_OTHER 2

# define WHERE "at file #a, line #l, function #f: "
// (look for syntax hightlighting error at SO xd)
# define LOG_ERROR_SIMPLE(ptr, lib, str) ptr->log ("ERROR " str \
                                                   " at library " #lib);
# define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE str)

LOG_ERROR_SIMPLE (this, LIB_SOME, "doing something")
LOG_ERROR (this, LIB_OTHER, "doing something else")

LOG_ERROR_SIMPLE()写入lib参数的字符串化(用“”包围的宏名)

但随后LOG_ERROR 写入已展开的宏的字符串化(“2”)。这是意料之中的,因为 lib 在扩展和调用 LOG_ERROR_SIMPLE 之前得到了扩展。但这不是我需要的。

基本上我的问题是:在调用另一个宏函数时如何避免宏函数参数的宏扩展?

我使用了一个技巧来避免宏扩展:

  LOG_ERROR(ptr, lib, str, x) LOG_ERROR_SIMPLE(ptr, x##lib, WHERE str)

  LOG_ERROR(this, LIB_OTHER, "some error",)

(粘贴 x 和 lib 生成 LIB_OTHER,此值用于调用 LOG_ERROR_SIMPLE,在调用之前未扩展宏)

有什么方法可以在不使用技巧的情况下获得相同的行为?

【问题讨论】:

    标签: c++ c macros c-preprocessor stringification


    【解决方案1】:

    我不认为你可以。但是,您可以做的是添加一层宏,以便在其位置上剥离:

    #define WRAP(x) x
    #define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, lib, WHERE WRAP(str))
    

    【讨论】:

    • @kts 哦,你知道的。我想到了一些事情,Boost 的研究人员远远领先于我。
    • WRAP 或 _IDENTITY 都不起作用.. 因为(至少在 CPP 中)它以 WRAP() 作为参数调用 LOG_ERROR_SIMPLE,而不是“名称中的内容但未扩展” "
    • 呃。在这种情况下,我认为您要么将 LOG_ERROR(ptr, lib, WRAP(str)) 强加给用户,要么写出 LOG_ERROR 而不参考 LOG_ERROR_SIMPLE。
    【解决方案2】:

    我在做:

    #include <cstdio>
    
    #define FOO 1
    #define BAR 2
    
    #define LOG_SIMPLE(ptr, lib, str) printf("%s\n", #lib);
    #define LOG(ptr, lib, str) LOG_SIMPLE(ptr, ##lib, str)
    
    int main()
    {
      LOG_SIMPLE(0, FOO, "some error");
      LOG(0, BAR, "some other error");
    }
    

    打印出来的:

    FOO
    BAR
    

    适用于 MSVC2005但不适用于 gcc/g++


    编辑:要使其与 gcc/g++ 一起使用,您可以滥用可变参数宏:

    #include <stdio.h>
    
    #define FOO 1
    #define BAR 2
    
    #define LOG_SIMPLE(ptr, str, lib) printf("%s\n", #lib);
    #define LOG(ptr, str, lib, ...) LOG_SIMPLE(ptr, str, lib##__VA_ARGS__)
    
    int main()
    {
      LOG_SIMPLE(0, "some error", FOO);
      LOG(0, "some other error", BAR);
      LOG(0, "some other error", FOO, BAR);
    }
    

    但是,您的原则是不要使用带有太多参数的宏。 MSVC2005 打印出来

    FOO
    BAR
    FOO2
    

    当 gcc 打印出来时

    FOO
    BAR
    FOOBAR
    

    【讨论】:

    • 使用 GCC 的预处理器(删除不存在的 #include)时,我在 stdout 上得到正确的程序,但在 stderr 上出现错误消息。 t.c:11:1:错误:粘贴“,”和“BAR”未提供有效的预处理令牌
    • 嗯,“不起作用”有点强。当我运行gcc -E t.c 时,我确实在标准输出上得到了一个可编译的程序。
    • 是的,粘贴是一种不扩展“lib 中的内容”并使其达到 LOG_SIMPLE 的方法。我之前的示例粘贴了带有空参数的 lib,您的粘贴了带有左逗号的 lib(这当然不是完全“正确的”)。我想知道是否可以使用“特殊的隐藏参数”粘贴 lib 以获得与在宏中使用额外参数相同的结果,为此目的交付时留空..
    • 是的,这是个好技巧!不幸的是,我已经在 LOG 和 LOG_SIMPLE 上使用了可变参数宏。为了简单起见,我没有指定它,这是我的错。这就是为什么我没有指望 VA_ARGS 作为以更优雅的方式粘贴任何内容的来源。
    • 我今天尝试了更多,但运气不佳,我们是否认为您无法避免一般情况下的扩展?
    【解决方案3】:

    你几乎拥有它。使用

    #define LOG_ERROR(ptr, lib, str) LOG_ERROR_SIMPLE(ptr, ##lib, WHERE str)
    

    在 gcc 上
    LOG_ERROR(this, LIB_OTHER, "some error")
    产量
    this-&gt;log ("ERROR " "at file #a, line #l, function #f: " "some error" " at library " "LIB_OTHER");

    我也会删除尾随的 ';'从您的宏中提取,以便您的代码如下所示:
    LOG_ERROR(this, LIB_OTHER, "some error")<strong>;</strong>

    【讨论】:

    • 我认为 OP 希望避免引用该论点,从而避免这个问题。如果“LIB_OTHER”对他没问题,我想他一开始就不会问
    • 用逗号粘贴 lib 会出现此错误:粘贴 "," 和 "LIB_OTHER" 不会提供有效的预处理令牌。是否有一些“中性”字符或隐藏的空参数我可以用来粘贴带有“空的东西”并且没有错误的库?
    • 对不起。我误解了你的需求。 BOOST_PP_EMPTY 是一个扩展为空的宏。你也可以试试 /**/ (这是一个空的 c 风格的注释,以防 markdown 杀死它)
    • 您能否提供所需的宏输出?给定 LOG_ERROR(this, LIB_OTHER, "some error) 你想生成什么代码?
    • @kts,它更多的是在宏方面本身,它的工作方式和宏扩展的方式,而不是 C 代码生成。我只是想对 LIB_OTHER 进行字符串化以获得“LIB_OTHER”.. 当然,LIB_OTHER 必须作为参数传递并在 2 级宏函数调用中幸存下来,这并非易事。
    【解决方案4】:

    如果您不需要 cpp 宏中的扩展库别名(即“1”和“2”),您也可以使用枚举而不是定义的值。

    【讨论】:

    • 虽然我很想找到我的宏扩展问题的解决方案,但你让我重新思考了其中的一个元素。我已将宏常量更改为枚举,它们的名称没有得到宏扩展(因为它们不是宏),现在问题没有解决,但它消失了 =)
    • 现在我仍然想解决它,但就我的程序而言,感谢您的建议我不需要..
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    相关资源
    最近更新 更多