zoukankan      html  css  js  c++  java
  • C语言宏基础总结

    最近在做一些项目的时候,不小心把NDK下面的一些宏写得有问题,导致一些编译不过的问题。所以,总结一下。
    这些知识都可以在 GCC 文档上找到,本文主要参考博文《C语言宏的特殊用法和几个坑》

    基础

    (1) 标示符别名

    #define PI 3.14159
    

    在预处理阶段:pi = PI结果是pi=3.14159;

    (2)宏函数
    宏名之后带括号的宏被认为是宏函数。用法和普通函数一样,只不过在预处理阶段,宏函数会被展开。优点是没有普通函数保存寄存器和参数传递的开销,展开后的代码有利于CPU cache的利用和指令预测,速度快。缺点是可执行代码体积大。

    #define min(X, Y)  ((X) < (Y) ? (X) : (Y))
    

    y = min(1, 2);会被扩展成y = ((1) < (2) ? (1) : (2));

    宏特殊用法

    (1)字符串化(Stringification)
    在宏体中,如果宏参数前加个#,那么在宏体扩展的时候,宏参数会被扩展成字符串的形式.如:

    #define WARN_IF(EXP) 
         do { if (EXP) 
                 fprintf (stderr, "Warning: " #EXP "
    "); } 
         while (0)
    

    调用是使用WARN_IF (x == 0);会被扩展成:

    do { if (x == 0)
        fprintf (stderr, "Warning: " "x == 0" "
    "); }
    while (0);
    

    这种用法可以用在assert中,如果断言失败,可以将失败的语句输出到反馈信息中。
    (2) 连接(Concatenation)
    在宏体中,如果宏体所在标示符中有##,那么在宏体扩展的时候,宏参数会被直接替换到标示符中。如:

    #define COMMAND(NAME)  { #NAME, NAME ## _command }
    
    struct command
    {
        char *name;
        void (*function) (void);
    };
    

    在宏扩展的时候

    struct command commands[] =
    {
        COMMAND (quit),
        COMMAND (help),
        ...
    };
    

    会被扩展成:

    struct command commands[] =
    {
        { "quit", quit_command },
        { "help", help_command },
        ...
    };
    

    注意事项:

    • 预处理器采取的策略是只展开一次, 如定义下面的宏:
    #define foo (4 + foo)
    

    交叉引用,宏体也只会展开一次,foo只会展开成(4 + foo),而展开之后foo的含义就要根据上下文来确定了。

    • 宏参数中若包含另外的宏,那么宏参数在被代入到宏体之前会做一次完全的展开,除非宏体中含有#或##
  • 相关阅读:
    CCF 201712-4 90分
    hdu2159
    ch11 持有对象
    ch7复用类
    PLSQL Developer 9注册码
    vue + typespript + webpack
    JavaScript 复制内容到剪贴板
    在不同电脑设备之间, 同步 VSCode 的插件和配置
    常用正则:提取内容, 格式化数字
    js css3 固定点拖拽旋转
  • 原文地址:https://www.cnblogs.com/ikaka/p/4934313.html
Copyright © 2011-2022 走看看