前言:下面是关于预处理部分的C语言详细语法介绍,其中也适当拓展了相关知识,有需要借鉴即可,
宏
数值宏常量
用宏来代替常量值意义何在?方便代码维护。
字符串宏常量
结论:宏定义代表字符串时,一定要带上双引号,可以选择性用续航符。
宏定义与注释
知识功底:
C语言文本文件 -> 二进制文件过程大概是四步
- 预处理(-E):去注释、展开头文件、宏替换、条件编译
- 编译(-S):把C语言翻译成汇编语言
- 汇编(-c):将汇编语言转换成可重定向目标文件(可被链接)
- 链接:链接库形成可执行程序
这四步骤的意义在哪?(为什么不是从C语言文本文件直接到二进制文件呢?)
这个问题涉及到计算机发展问题,在上世纪五六十年代,诞生了计算机,而最初的计算机文件程序是用二进制进行编写的,一大堆科学家围着计算机算二进制。后来为了编写方便,诞生了汇编语言。之后为了更加贴合人类的语言,又相继诞生了C语言、Java、Python等高级语言。
在高级语言出现之后,这里就涉及到如何将高级语言转换成二进制的问题了,人们为了方便,就采用的下图中方案1进行设计翻译(因为之前已经有汇编到二进制的翻译,所以比较方便)。
思考:先有编译器还是先有高级语言?
结论:预处理期间:先执行去注释,再进行宏替换
关于宏理解的几个问题
A:是。
B:可以,只不过替换过来什么都没有而已。
C:结论:用双引号引起来的宏是一种字符串常量
D:不是,属于字符串常量
E:
结论:当我们需要宏进行多语句替换的时候, 推荐使用do-while-zero结构。
宏定义中的空格
#undef问题
#undef其实就是联系到宏定义的作用域问题了。
问题1:宏定义有位置限制吗?没有,任何地方都可以进行宏定义。
问题2:
结论:宏的作用域是哪里?自宏定义后往下(物理层面,这里并不是指逻辑结构),直到碰到#undef
为什么?因为预处理先于编译,编译之后代码才有逻辑一说。
问题3:#undef是做什么的?取消宏定义的,下面不再多做解释。
关于C深剖书中的规则推荐:
条件编译
条件编译的本质:裁剪代码
#ifdef与#ifndef:宏是否被定义
这里重点区分,宏是否被定义,宏定义为假,宏定义为真这三组概念即可。
宏定义的时机
在宏定义方面,宏支持在编写代码时定义,也支持在编译过程中进行定义。
#if
#if可以与多组#elif进行联用(如下图)
#if可以模拟#ifdef(如下图)
模拟多组#ifdef逻辑与:
当然,#if也支持嵌套
小总结:
条件编译的典型应用——解决头文件重复包含的问题
其他预处理符号介绍
#error
作用:自定义编辑报错,提示,并中止程序
#line
作用:自定义更改行号和文件名
#pragma
1.#pragma message用于自定义提示信息
注:与#error的区别在于,message只停留在编译器提示层面,error直接报错并终止程序
2.#pragma once 头文件只包含一次
3.#pragma pack 用于指定内存对齐
4.#prama warning 忽略编译器报错信息
#号
#传过来的参数字符串化
##号
##将##连接的两个符号,链接成为一个符号