C语言宏基础总结

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

基础

(1) 标示符别名git

#define PI 3.14159

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

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

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

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

宏特殊用法

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

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

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

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

这种用法能够用在assert中,若是断言失败,能够将失败的语句输出到反馈信息中。htm

(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的含义就要根据上下文来肯定了。

  • 宏参数中若包含另外的宏,那么宏参数在被代入到宏体以前会作一次彻底的展开,除非宏体中含有#或##
相关文章
相关标签/搜索