我们可以在多行中编写一个宏,而且末尾没有反斜杠吗? [英] Can we write a macro in many lines without the backslash at the end?

查看:377
本文介绍了我们可以在多行中编写一个宏,而且末尾没有反斜杠吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在CPP手册中看到了一些例子,我们可以在没有反斜杠的情况下在许多行中编写宏体。

  #define奇怪(文件)fprintf(文件,%s%d,
...










  fprintf(stderr,%s%d,p,35)

对于包含指令,它必须始终声明如果我没有错的话,请在一行上。



编辑

A HREF = https://gcc.gnu.org/onlinedocs/cpp/Directives-Within-Macro-Arguments.html 相对= nofollow noreferrer> https://gcc.gnu.org/onlinedocs/cpp/Directives -Within-Macro-Arguments.html


3.9宏指令中的指令



偶尔
中使用宏中的预处理指令很方便
。 C和C ++标准声明这些情况下的
行为是未定义的。 GNU CPP在宏参数中处理任意的
指令,其方式与
处理指令的方式完全相同,类似于函数式宏调用
不存在。



如果在宏调用中重新定义该宏,那么新的
定义将在参数预扩展中及时生效,但
原始定义仍然用于参数替代。这是一个
的病理例子:

  #define f(x)xx 
f(1
#undef f
#define f 2
f)

扩展到

  1 2 1 2 


$

这个例子有许多行。

解决方案

没有多线宏定义反斜杠换行符



由于注释由在翻译相空间置换3:





  • 源文件被分解成预处理标记 7)
    空白字符(包括注释)的序列。源文件不得以
    部分预处理令牌或部分注释结束。每个评论由
    替换为一个空格字符。换行符保留。是否保留每个非空白
    序列的除空行以外的空白字符或由
    替换一个空格字符是否是实现定义的。


  • 并且预处理器作为阶段4运行:
    $ b



    1. 执行预处理指令,扩展宏调用,并执行
      _Pragma 一元运算符表达式。如果
      与通用字符名称的语法匹配的字符序列由标记
      concatenation(6.10.3.3)生成,则行为未定义。一个 #include 预处理
      指令会导致指定的头文件或源文件在阶段1中以
      的形式递归处理。然后删除所有预处理指令。


    如下所示:

      #include< stdio.h> 

    #define possible_but_absurd(a,b)/ *注释
    * / printf(被翻译); / *在阶段3
    * / printf(阶段%d之前,a); / *(预处理器)
    * / printf(正在运行(%s)\\\
    ,b); / *但为什么滥用系统? * /

    int main(void)
    {
    printf(%s%s,宏可以继续反斜杠,
    因为comments \
    );
    possible_but_absurd(4,ISO / IEC 9899:2011,\第5.1.1.2节
    翻译阶段);
    返回0;
    }

    其中,运行时指出:

     宏可以在没有反斜杠的情况下继续,因为在执行阶段4之前翻译注释
    (ISO / IEC 9899:2011,
    章节5.1.1.2翻译阶段)



    宏定义中的反斜线 - 换行符



    翻译阶段1和2也有些相关:



    1. 映射物理源文件多字节字符,以实现定义的
      的方式,如果需要的话,添加到源字符集(为
      行末指标引入新行字符)。 Trigraph序列被替换为
      相应的单字符内部表示。


    三字母替换是名义上相关的,因为 ?? / 是反斜杠的三字符。



    1. 删除每一个反斜线字符( \ )后面紧跟一个换行符
      的实例,并将其拼接物理源线来形成逻辑源线。
      只有任何物理源线上的最后一个反斜杠才有资格作为这种拼接的一部分
      。非空的源文件应以新行字符
      结尾,在执行任何此类
      拼接之前,不应立即在前面加上反斜杠字符。


    这告诉你,在阶段4(预处理器)运行时,宏定义位于单一(逻辑)行上 - 尾部反斜杠 - 换行符组合已被删除。



    标准提示阶段是'as if' - 编译器的行为必须像是通过单独的阶段,但很多实现并未正式将它们完全分开。






    避免GCC扩展



    扩展示例(引用GCC手册)将调用分散在多行中,但定义严格限于一行。 (这不是GCC的扩展,但完全标准的行为。)注意,如果你是远程理智的,你会忽略把预处理指令放在调用一个宏(例子中的 #undef #define )。这是一个GCC扩展,完全不可移植。该标准表示该行为未定义。


    附件J.2未定义行为




    • 有很多宏参数,否则将作为预处理指令列表(6.10.3)内预处理标记的序列。



    I saw some examples in CPP manual where we can write macros body in many lines without the backslash.

     #define strange(file) fprintf (file, "%s %d",
     ...
     strange(stderr) p, 35)
    

    output:

    fprintf (stderr, "%s %d", p, 35)
    

    Are they special cases like directives inside arguments macros or is it allowed only for #define ?

    For include directives It must be always declared on one line if I am not wrong.

    Edit:

    From https://gcc.gnu.org/onlinedocs/cpp/Directives-Within-Macro-Arguments.html

    3.9 Directives Within Macro Arguments

    Occasionally it is convenient to use preprocessor directives within the arguments of a macro. The C and C++ standards declare that behavior in these cases is undefined. GNU CPP processes arbitrary directives within macro arguments in exactly the same way as it would have processed the directive were the function-like macro invocation not present.

    If, within a macro invocation, that macro is redefined, then the new definition takes effect in time for argument pre-expansion, but the original definition is still used for argument replacement. Here is a pathological example:

     #define f(x) x x
     f (1
     #undef f
     #define f 2
     f)
    

    which expands to

     1 2 1 2
    

    with the semantics described above.

    The example is on many lines.

    解决方案

    Multi-line macro definitions without backslash-newline

    Since comments are replaced by spaces in translation phase 3:

    1. The source file is decomposed into preprocessing tokens7) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment. Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.

    and the preprocessor runs as phase 4:

    1. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is produced by token concatenation (6.10.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1. through phase 4, recursively. All preprocessing directives are then deleted.

    it is possible, but absurd, to write a multi-line macro like this:

    #include <stdio.h>
    
    #define possible_but_absurd(a, b)     /* comments
        */ printf("are translated");      /* in phase 3
        */ printf(" before phase %d", a); /* (the preprocessor)
        */ printf(" is run (%s)\n", b);   /* but why abuse the system? */
    
    int main(void)
    {
         printf("%s %s", "Macros can be continued without backslashes",
                         "because comments\n");
         possible_but_absurd(4, "ISO/IEC 9899:2011,\nSection 5.1.1.2"
                                " Translation phases");
         return 0;
    }
    

    which, when run, states:

    Macros can be continued without backslashes because comments
    are translated before phase 4 is run (ISO/IEC 9899:2011,
    Section 5.1.1.2 Translation phases)
    

    Backslash-newline in macro definitions

    Translation phases 1 and 2 are also somewhat relevant:

    1. Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences are replaced by corresponding single-character internal representations.

    The trigraph replacement is nominally relevant because ??/ is the trigraph for a backslash.

    1. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.

    This tells you that by the time phase 4 (the preprocessor) is run, macro definitions are on a single (logical) line — the trailing backslash-newline combinations have been deleted.

    The standard notes that the phases are 'as if' — the behaviour of the compiler must be as if it went through the separate phases, but many implementations do not formally separate them out fully.


    Avoid the GCC extension

    The expanded example (quote from the GCC manual) has the invocation spread over many lines, but the definition is strictly on one line. (This much is not a GCC extension but completely standard behaviour.)

    Note that if you're remotely sane, you'll ignore the possibility of putting preprocessing directives within the invocation of a macro (the #undef and #define in the example). It is a GCC extension and totally unportable. The standard says that the behaviour is undefined.

    Annex J.2 Undefined behavior

    • There are sequences of preprocessing tokens within the list of macro arguments that would otherwise act as preprocessing directives (6.10.3).

    这篇关于我们可以在多行中编写一个宏,而且末尾没有反斜杠吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆