
1宏定义列表是无先后顺序要求的。最近我在看我同事的源代码并根据我自己的理解重新编写因为我同事写的代码比较集中并且没有注重分模块、分层思想而我现在编写代码的思路是“写代码就是对事物细节的描述”因此使用到了大量的宏定义来描述模块的属性其中就有这样一种情况我需要定义一个宏描述一行命令中有效数据的个数也是就说宏值需要用到一个全局变量 但是这个全局变量的声明是写在宏定义的后面如下所示#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次替代关系后变成了extern uint8_t cmd_rxlen, cmd_txlen; cmd_rxlen-4因此编译器编译的时候就不会报错。注意值得注意的事我在上述案例中使用宏定义去描述一个可变量也就是有效数据长度是由一个命令字节若干个有效数据字节构成这样是不太合适的。因为宏定义往往用于描述不变的、恒定的、常量不太适合描述这种能够在代码运行阶段变动的变量。如果某一个元素是变动的用变量的方式去描述是比较合适的。详情请看文章代码就是对事物细节的描述2宏值为未定义情况只要不使用宏名也不会报错。我们编写代码的时候用代码描述模块的细节有些细节只是因为我们需要对模块的细节进行描述转换为代码但是实际并不会使用到这个时候就可能使用未定义的宏值。如下情况define CMD_FOURTH_BYTE CMD_X #define CMD_USB5V_1 0x01第一个宏定义的意思是表示cmd行的低四个字节表示某一个命令CMD_X但是这个命令CMD_X是抽象的意思是某一个命令我们后面源文件中编写代码实际使用的是后面的宏名CMD_USB5V_1等这种具体的命令当编译的时候因为我们没有使用的宏名CMD_FOURTH_BYTE因此也不会发生替代行为因此编译器也不会报错。心得一次宏调用就对应一次替代行为发生宏定义中的宏值其实就是一个标识符如果不存在宏调用的发生宏值这个标识符未被定义也是允许的。时刻牢记宏定义和宏调用对应的是标识符的对应关系和标识符的替代关系预处理器只负责完成存在的替代行为并不关系标识符合不合法是否存在这些工作是编译器的工作。