使用以前未定义的宏时不会出现编译器错误
No compiler error when macros that weren't previously defined are used
请问为什么下面的代码编译器不报错?
这是 flash.h 文件:
#ifndef _FLASH_H_
#define _FLASH_H_
#define BANK_A 0
#define BANK_B 1
#define BANK_C 3
#define FLASH_IS_BUSY (FCTL3 & BUSY)//FCTL3 and BUSY are defined in msp430f5438a.
#endif
这是 main.c 文件:
#include "flash.h"
#include <msp430f5438a.h>
void main(void)
{
while(1)
{
;
}
}
问题是我不明白编译器为什么不在这一行报错:
#define FLASH_IS_BUSY (FCTL3 & BUSY)
因为(据我所知)编译器无法知道FCTL3和BUSY是什么意思。这两个宏在 msp430f5438a.h 中定义如下:
#define FCTL3 (*((unsigned char*)0x0144u))
#define BUSY 0x01
但是 flash.h 包含在 msp430f5438a.h 之前 编译器如何解析这些符号:FCTL3 和 BUSY?
这里要注意的是,#define
在预处理阶段作为文本替换,它们与变量声明或定义不同。
在您的 header 文件中,您只定义了 FLASH_IS_BUSY
宏,但在您的代码中,您没有使用它。甚至,如果您使用过它,在 main()
之前,header #include <msp430f5438a.h>
就在那里,这使得 FCTL3
和 BUSY
的定义对您可用代码,如果使用的话。
TL;DRFLASH_IS_BUSY
宏定义在header文件中不需要FCTL3
和 BUSY
已经被定义。例如,您可以使用 -D
选项和 gcc
提供这些 MACRO 值,它们根本不需要出现在代码中。
也就是说,main()
的推荐签名是int main(void)
您没有使用FLASH_IS_BUSY
,所以预处理器不会替换不正确的语法。
顺便说一下,在较旧的 C 标准(和较新的 C++ 标准)中编写 while(1);
时要小心,因为您的程序的行为是未定义的。
见Is while(1); undefined behavior in C?
限制您问题的特定主题(预处理器替换),其中:
#define FLASH_IS_BUSY (FCTL3 & BUSY)
您没有以任何方式使用 FCTL3
和 BUSY
。您只是在指示编译器执行文本替换。它不需要知道任何关于它们的信息。
然而,当您像这样在代码中使用它时:
int flags = FLASH_IS_BUSY;
它将执行第一次替换:
int flags = (FCTL3 & BUSY);
替换循环将继续,直到有东西要替换(或达到硬阈值)。如果你忘记包含 msp430f5438a.h
那么上面的代码将不会简单地编译(因为 FCTL3
和 BUSY
是未知的),但是如果你包含正确的头文件(无论顺序如何:msp430f5438a.h
首先或 flash.h
首先)它们将被预处理器替换为它们的实际值,您将拥有正确的代码:
int flags = ((*((unsigned char*)0x0144u)) & 0x01);
现在预处理器完成,编译器(启用优化时)将(可能!!!)直接用文字值替换 flags
。
备注:
- 您的
main()
签名不标准。它应该(对于托管环境)为 int main(void)
或 int main(int argc, char* argv[])
。另见 What is the proper declaration of main?. Note that if your compiler allows void main(void)
signature then it's not wrong but it's just non-standard. However Lunding highlighted that in freestanding environments main()
function, according to C standard, signature is completely implementation-defined. See his enlightening post: Why is the type of the main function in C and C++ left to the user to define?
- 我知道
while(1)
只是说明性的(它不是您的 真实的 代码)但它可能是早期 C 规范中的 UB。我不会在这里重复这个(长)讨论然后请参考 Are compilers allowed to eliminate infinite loops? 进一步研究。
u
后缀不是必需的,在 C 中整数文字总是非负的,那么 u
只是多余的。然而,某些特定准则(例如在关键系统中,请参阅 MISRA)可能 要求 明确(向读者)常量旨在成为非负整数。
- 您的空循环可能会被简单地优化掉。编译器可以自由选择不为
;
生成任何代码。 Various workarounds exists 如果你想让它便携。
请问为什么下面的代码编译器不报错? 这是 flash.h 文件:
#ifndef _FLASH_H_
#define _FLASH_H_
#define BANK_A 0
#define BANK_B 1
#define BANK_C 3
#define FLASH_IS_BUSY (FCTL3 & BUSY)//FCTL3 and BUSY are defined in msp430f5438a.
#endif
这是 main.c 文件:
#include "flash.h"
#include <msp430f5438a.h>
void main(void)
{
while(1)
{
;
}
}
问题是我不明白编译器为什么不在这一行报错:
#define FLASH_IS_BUSY (FCTL3 & BUSY)
因为(据我所知)编译器无法知道FCTL3和BUSY是什么意思。这两个宏在 msp430f5438a.h 中定义如下:
#define FCTL3 (*((unsigned char*)0x0144u))
#define BUSY 0x01
但是 flash.h 包含在 msp430f5438a.h 之前 编译器如何解析这些符号:FCTL3 和 BUSY?
这里要注意的是,#define
在预处理阶段作为文本替换,它们与变量声明或定义不同。
在您的 header 文件中,您只定义了 FLASH_IS_BUSY
宏,但在您的代码中,您没有使用它。甚至,如果您使用过它,在 main()
之前,header #include <msp430f5438a.h>
就在那里,这使得 FCTL3
和 BUSY
的定义对您可用代码,如果使用的话。
TL;DRFLASH_IS_BUSY
宏定义在header文件中不需要FCTL3
和 BUSY
已经被定义。例如,您可以使用 -D
选项和 gcc
提供这些 MACRO 值,它们根本不需要出现在代码中。
也就是说,main()
的推荐签名是int main(void)
您没有使用FLASH_IS_BUSY
,所以预处理器不会替换不正确的语法。
顺便说一下,在较旧的 C 标准(和较新的 C++ 标准)中编写 while(1);
时要小心,因为您的程序的行为是未定义的。
见Is while(1); undefined behavior in C?
限制您问题的特定主题(预处理器替换),其中:
#define FLASH_IS_BUSY (FCTL3 & BUSY)
您没有以任何方式使用 FCTL3
和 BUSY
。您只是在指示编译器执行文本替换。它不需要知道任何关于它们的信息。
然而,当您像这样在代码中使用它时:
int flags = FLASH_IS_BUSY;
它将执行第一次替换:
int flags = (FCTL3 & BUSY);
替换循环将继续,直到有东西要替换(或达到硬阈值)。如果你忘记包含 msp430f5438a.h
那么上面的代码将不会简单地编译(因为 FCTL3
和 BUSY
是未知的),但是如果你包含正确的头文件(无论顺序如何:msp430f5438a.h
首先或 flash.h
首先)它们将被预处理器替换为它们的实际值,您将拥有正确的代码:
int flags = ((*((unsigned char*)0x0144u)) & 0x01);
现在预处理器完成,编译器(启用优化时)将(可能!!!)直接用文字值替换 flags
。
备注:
- 您的
main()
签名不标准。它应该(对于托管环境)为int main(void)
或int main(int argc, char* argv[])
。另见 What is the proper declaration of main?. Note that if your compiler allowsvoid main(void)
signature then it's not wrong but it's just non-standard. However Lunding highlighted that in freestanding environmentsmain()
function, according to C standard, signature is completely implementation-defined. See his enlightening post: Why is the type of the main function in C and C++ left to the user to define? - 我知道
while(1)
只是说明性的(它不是您的 真实的 代码)但它可能是早期 C 规范中的 UB。我不会在这里重复这个(长)讨论然后请参考 Are compilers allowed to eliminate infinite loops? 进一步研究。 u
后缀不是必需的,在 C 中整数文字总是非负的,那么u
只是多余的。然而,某些特定准则(例如在关键系统中,请参阅 MISRA)可能 要求 明确(向读者)常量旨在成为非负整数。- 您的空循环可能会被简单地优化掉。编译器可以自由选择不为
;
生成任何代码。 Various workarounds exists 如果你想让它便携。