c语言编写过程中宏定义的中两种情况

(1)宏定义列表是无先后顺序要求的。

最近,我在看我同事的源代码,并根据我自己的理解重新编写,因为我同事写的代码比较集中,并且没有注重分模块、分层思想,而我现在编写代码的思路是"写代码就是对事物细节的描述",因此使用到了大量的宏定义来描述模块的属性,其中就有这样一种情况:

我需要定义一个宏,描述一行命令中有效数据的个数,也是就说宏值需要用到一个全局变量 ,但是这个全局变量的声明是写在宏定义的后面,如下所示:

cpp 复制代码
#define CMD_FOMAT_BYTE                  0x04        /**命令中的格式字节个数 */
#define CMD_DATA_LENTH                  (cmd_rxlen - CMD_FOMAT_BYTE) 

extern uint8_t cmd_rxlen, cmd_txlen;

也就是我使用的宏值中有一个"标识符",是在后面的代码中声明的。

请问:如果后面我使用到了宏名CMD_DATA_LENTH,那么编译器会不会报错呢?

答案:编译器并不会报错。

以前的错误认识:我以前认为宏定义(多个宏定义组成了列表)和变量、函数等代码实体是有先后顺序要求的,这种想法是错误的。宏定义(列表)是没有先后顺序的,只是告诉预处理器存在的替代列表,宏定义(列表)经过预处理器读取后,暂存在预处理器中的缓存,而非存在代码中,预处理器读取代码如果发现了标识符在缓存中就用宏值替代,这也是为什么宏定义有些是在源代码开头位置定义,有些是在代码段的上面定义的原因。预处理器首先将源文件中所有的宏定义都读到预处理器的缓存其中保存着,然后再去逐行阅读代码并将宏名使用宏值替代。

上面的宏值CMD_DATA_LENTH在源文件中被调用,预处理器处理源文件,首先cmd_rxlen这个全局变量是被声明了的,也就是已知的,而CMD_FOMAT_BYTE在预处理器的缓存中存储着,并且宏值为0x04,总共发生2次替代关系后变成了:

cpp 复制代码
extern uint8_t cmd_rxlen, cmd_txlen;

cmd_rxlen-4

因此编译器编译的时候就不会报错。

(2)宏值为未定义情况,只要不使用宏名,也不会报错。

我们编写代码的时候,用代码描述模块的细节,有些细节只是因为我们需要对模块的细节进行描述,转换为代码,但是实际并不会使用到这个时候就可能使用未定义的宏值。如下情况:

cpp 复制代码
define CMD_FOURTH_BYTE                 CMD_X
#define CMD_USB5V_1                     0x01

第一个宏定义的意思是表示cmd行的低四个字节表示某一个命令CMD_X,但是这个命令CMD_X是抽象的,意思是某一个命令,我们后面源文件中编写代码实际使用的是后面的宏名CMD_USB5V_1等这种具体的命令,当编译的时候因为我们没有使用的宏名CMD_FOURTH_BYTE,因此也不会发生替代行为,因此编译器也不会报错。

心得:一次宏调用就对应一次替代行为发生,宏定义中的宏值其实就是一个标识符,如果不存在宏调用的发生,宏值这个标识符未被定义也是允许的。

时刻牢记:宏定义和宏调用对应的是标识符的对应关系和标识符的替代关系,预处理器只负责完成存在的替代行为,并不关系标识符合不合法,是否存在,这些工作是编译器的工作。