去注释和宏替换——深入理解预处理

去注释

image-20220912162150009

image-20220912162016566

我们对文件test.i只进行预处理操作,打开test.i和test.c,我们发现原来在test.c中被注释的几行代码在预处理后的test.i中不存在了。这就是预处理操作中的去注释。

宏替换

image-20220912162902372

image-20220912162828434

可以发现,#define定义的标识符常量和宏都在预处理阶段被替换了。这就是宏替换

而对于这个宏替换还有一个小细节,我之前的博客写过#define的#和define之间是可以有空格的,那么这里将要说的是:我们在使用宏时宏的名字和括号也是可以隔空格的。

image-20220912163354505

代码正常运行,没有任何的错误和警告,但要注意的一点是:在定义宏的时候名字和括号之间是不能有空格的,只有在使用宏的时候名字和括号之间才可以存在空格。

image-20220912163634175

**注意:**关于#和define之间可以存在空格和使用宏时名字和括号之间可以存在空格,这个知识点我们只需要了解即可,当我们在编写代码的时候严格不推荐这种写法。

去注释和宏替换哪个先执行呢?

image-20220912164358233

我们将注释符号//使用#define 定义成BSC,去注释和宏替换哪个先执行,无非就两种情况。

  1. 宏替换先执行

    那么最终的结果应该是什么也不输出,因为BSC先被替换成//,然后再去注释,这一行代码就会被去掉,所以什么也不输出。

  2. 去注释先执行

    最终的结果应该是输出you can see me,第一步先去注释,会把#define BSC //中的//去掉(//本身也是注释),那么这一句就会变成#define BSC ,而我们知道在#define定义标识符常量时,可以不写内容。再下一步执行宏替换时BSC会被替换成空,那么代码就会变为printf("you can see me!\n");,该代码当然可以正常输出了。

而根据我们上图的结果,我们可以确定结论:去注释是先于宏替换的!

那么对如下代码如何理解呢?

#include <stdio.h>
#define BMC /*
#define EMC */
int main()
{
    BMC printf("you can see me!\n"); EMC
    return 0;
}

image-20220912170239973

image-20220912170532647

可以看到,test.i中经过预处理操作后内容变成了这样,这样的代码当然不会运行成功了。

test.c到test.i的转变过程(预处理):先去注释,把上图右边绿色的给删除掉,宏定义就只剩下#defien BMC然后再进行宏替换,将BMC替换成空,那EMC呢?EMC此时就是一个未命名的符号,导致编译错误。

宏进行多语句替换

平常我们使用宏,一般都是定义标识符常量,一个标识符代表一个单词或数字,然后免不了有一种情况就是使用宏来进行多语句的替换。也就是一个宏的标识符代表多个语句。

#include <stdio.h>
#define INIT_VALUE(a, b)\
		a = 0;\
		b = 0;
int main()
{
    int flag = 0;
    scanf("%d", &flag);
    int a = 100;
    int b = 200;
    printf("before: %d %d\n", a, b);    
    if(flag)
        INIT_VALUE(a, b);
    else
        printf("error!\n");
    printf("after: %d %d\n", a, b);
    return 0;
}

image-20220912172336154

我们知道在使用if、else时如果不加{},则默认if和else之后各自只能写“一条语句”,而看上图,我们很明显符合这一规律啊,我们来预处理一下看看什么情况。

image-20220912172759806

仔细查看,发现宏替换后,if后面跟了三条语句,从而导致else无法与if构成系统,导致出错。

解决这一问题很简单,只要我们有一个良好的书写风格,也就是无论if、else后跟几条语句,我们统统都加上{},也就不会导致这样的错误。但是我们要清楚,一个良好的代码,是需要能够具有普适性的,也就是在面对恶劣的环境下也尽量能够运行成功,所以我们这里的修改方案不能是增加if、else后面的括号,而是要对宏进行修改。

来看下面的代码

#include <stdio.h>
#define INIT_VALUE(a, b)\
do{\
	a = 0;\
	b = 0;\
}while(0)
int main()
{
    int flag = 0;
    scanf("%d", &flag);
    int a = 100;
    int b = 200;
    printf("before: %d %d\n", a, b);    
    if(flag)
        INIT_VALUE(a, b);
    else
        printf("error!\n");
    printf("after: %d %d\n", a, b);
    return 0;
}

image-20220912173909961

image-20220912174106565

为什么使用的是do-while-zero结构呢?因为当if为真时,我们必须要执行INIT_VALUE,而我们只执行一次,do-while-zero的结构完美的解决了必须要执行并且只执行一次的条件。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云朵c

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值