第1章-预处理器阶段

  • 1)c代码->预处理器处理->编译->...
  • 2)宏只是对程序的“文本”起作用,预处理器阶段对宏进行了展开。

一、不能忽视宏定义中的空格

  • 测试目标:
    用宏模拟一个函数f(x)=x*2的行为
    Tips:“宏”和“函数”是两回事

1)testOne.c

//testOne.c
#include<stdio.h>

#define f(x) x*2

int main()
{
    int num=f(3);
    printf("%d\n",num);
    return 0;
}
//输出
//6

人工模拟“预处理器”过程
上述test.c经过“预处理器”展开之后的样子如下:

//testOne.c宏展开之后
#include<stdio.h>

int main()
{
    //关注点如下,只做文本替换
    int num=3*2;
    printf("%d\n",num);
    return 0;
}

2)testTwo.c

//testTwo.c
#include<stdio.h>
//注意,f和(x)之间已经有个空格了
#define f (x) x*2
int main()
{
    int num=f(7);
    printf("%d\n",num);
    return 0;
}
//输出
//编译错误

解释:此处,f文本将被替换为(x) x2 *文本**

所以,不能忽视宏定义中的空格

二、宏并不是“函数”

testOne.c中,那种模拟宏的方式其实是不够严谨的
比如,要是喜欢认为这种定义宏就是“函数”的人,可能会认为testThree.c会输出0?

//testThree.c
#include<stdio.h>

#define f(x) x*2

int main()
{
    int num=f(7-7);
    printf("%d\n",num);
    return 0;
}
//输出
//-7

原因:宏它就是“宏”,不要用其他特性来揣测它
宏的特点就是在“预处理器阶段”进行文本替换

//testThree.c宏展开之后
#include<stdio.h>
int main()
{
    int num=7-7*2;
    printf("%d\n",num);
    return 0;
}
//输出
//-7

为了预防这种文本一环,引起的由于“优先级”而导致“事与愿违”的现象
建议:

  • 1、在宏定义中把“每个参数”都用括号括起来
  • 2、将“整个结果表达式”也都用括号括起来
#define f(x) x*2
修改为下面的样子
#define f(x) ( (x) *2 )

三、宏并不是“语句”

四、宏并不是“类型定义”

//编译条件,DevC++,32bit
#include<stdio.h>

#define one double *

typedef double * two;

int main()
{
    one a,b;
    printf("%d %d\n",sizeof(a),sizeof(b));

    two c,d;
    printf("%d %d\n",sizeof(c),sizeof(d));
    return 0;
}
//输出
//4 8
//4 8

宏展开之后,关键部分

one a,b;
//预处理阶段,宏展开为
double * a,b;//a是指针变量,b是普通变量

two c,d;
//编译阶段处理后,c和d都是指针变量

附)总结

  • 1、宏只是对程序的“文本”起作用,预处理器阶段对宏进行了展开。
  • 2、建议
    • 在宏定义中把“每个参数”都用括号括起来
    • 将“整个结果表达式”也都用括号括起来
  • 3、宏和“函数”/“语句”/“类型定义”等的不同,本质在于,宏是文本替换。