【问题标题】:Macros as arguments to preprocessor directives宏作为预处理器指令的参数
【发布时间】:2009-11-15 05:11:35
【问题描述】:

面对是否可以在预处理器中选择#includes 的问题时,我立即认为不可能
.. 只是后来发现它确实是可能的,你只需要注意参数扩展(例如 Boost.Preprocessor 可以处理)。

虽然我会尽可能避免为包含实际执行此操作,但我想知道为什么会这样。目前我无法对 C++ 或 C 标准有一个有用的理解。
任何预处理器指令都允许参数化宏吗? (#define/#undef除外)
有人可以参考允许这样做的地方并进行总结吗?

为简单起见,使用 Boost.Preprocessor 的好奇示例:

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>

#define INC_LOCAL(a,b)  BOOST_PP_STRINGIZE(BOOST_PP_CAT(BOOST_PP_CAT(a,b),.h))
#define INC_GLOBAL(a,b) BOOST_PP_CAT(BOOST_PP_CAT(<,a),BOOST_PP_CAT(b,>))

#include INC_LOCAL(loc,al)   // #include "local.h"
#include INC_GLOBAL(vect,or) // #include <vector>

更新: 引用 C 标准,澄清问题。

【问题讨论】:

    标签: c++ macros c-preprocessor


    【解决方案1】:

    来自 C++ 2003 草案的第 16.2-4 节(“源文件包含”):

    形式的预处理指令

    # include pp-tokens new-line 
    

    (与前两种形式之一不匹配)是允许的。指令中include 之后的预处理标记的处理方式与普通文本一样(当前定义为宏名称的每个标识符都被其预处理标记的替换列表替换)。

    C99 的第 6.10.2-4 节也这么说。

    上面提到的“前两种形式”是# include &lt;h-char-sequence&gt;# include "q-char-sequence"。该部分似乎太简单而无法概括。

    对于其他指令,不会对任何 identifier 预处理标记执行宏扩展(请注意,此行为不是由语法定义,而是由 C++ § 16 / C § 6.10 定义):

    # if constant-expression new-line [group] 
    # ifdef identifier new-line [group] 
    # ifndef identifier new-line [group] 
    # elif constant-expression new-line [group] 
    # else new-line [group] 
    # endif new-line 
    # include pp-tokens new-line 
    # define identifier replacement-list new-line 
    # define identifier lparen [identifier-list] ) replacement-list new-line 
    # undef identifier new-line 
    # line pp-tokens new-line 
    # error [pp-tokens] new-line 
    # pragma [pp-tokens] new-line 
    # new-line 
    

    #line 由 C++ § 16.4-5 / C § 6.10.4-5 显式地进行宏扩展。未提及 #error (C++ § 16.5 / C § 6.10.5) 和 #pragma (C++ § 16.6 / C § 6.10.6) 的扩展。 C++ § 16.3-7 / C 6.10.3-8 状态:

    如果 # 预处理标记,后跟标识符,在词法上出现在预处理指令可以开始的位置,则标识符不受宏替换的影响。

    C++ § 16.3.1 / C § 6.10.3.1-1 告诉我们,当宏函数的参数被替换到 replacement-list 时,它们首先被宏扩展。同样,C++ § 16.3.4 / C § 6.10.3.4 具有预处理器宏扩展 replacement-list 替换后。

    总之,宏扩展是针对#if#elif#include#line、宏函数的参数和宏函数的主体在被替换时完成的。我想这就是一切。

    【讨论】:

    • 好吧,pp-tokens 将我带到preprocessing-token,从那里只有preprocessing-op-or-punc 看起来不错,但只提供了一些运算符。
    • 所以are processed just as in normal text 意味着像identifier(identifier, ...) 这样的宏扩展?
    • 当然。结果可能具有未定义的行为。
    • 我很高兴你能理解任何东西......虽然我不时使用 BOOST_PP 宏,但这对我来说都是魔法!我想我必须一遍又一遍地阅读这个回复:/
    • 阅读标准是一项学习技能。你接触它的次数越多,它就越容易。任何话语都是如此。
    【解决方案2】:

    这是 C 预处理器的一个非常基本的特性——例如,当与可能是宏的参数一起使用时,#ifdef 之类的指令为零意义except(如果你必须知道参数不允许是宏,#ifdef 的目的可能是什么?!)。

    我不确定 ISO C 标准的章节对你有什么帮助——我记得 C++ 标准并没有改变预处理器的操作。

    【讨论】:

    • 更正:我现在很困惑参数化宏是否只允许在任何 pp 指令中使用,并希望澄清这一点。
    猜你喜欢
    • 2012-05-27
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    相关资源
    最近更新 更多