我想问你为什么在下面的代码中编译器没有给出错误? 这是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
但是在msp430f5438a.h之前包含了flash.h.编译器如何解析这些符号:FCTL3和BUSY?
答案 0 :(得分:3)
需要注意的是,#define
在预处理阶段作为文本替换,它们与变量声明或定义不同。
在您的标头文件中,您只定义了FLASH_IS_BUSY
MACRO,但在您的代码中,您还没有使用它。即使如果你已经使用过,main()
之前,标题#include <msp430f5438a.h>
就在那里,这使得代码可以使用FCTL3
和BUSY
的定义,如果使用的话
TL; DR 标头文件中的FLASH_IS_BUSY
宏定义不需要FCTL3
和BUSY
定义。例如,您可以使用-D
gcc
选项提供这些MACRO值,它们根本不需要出现在代码中。
尽管如此,main()
的推荐签名是int main(void)
答案 1 :(得分:2)
限制您的问题的特定主题(预处理器替换),使用:
#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?。请注意,如果您的编译器允许void main(void)
签名,那么它不是错误,但它的只是非标准。然而,Lunding强调,在独立环境main()
函数中,根据C标准,签名完全是实现定义的。见他的启发性帖子: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)可能 required 以明确(对于读者)一个常量是非负整数。 ;
生成任何代码。 Various workarounds exists如果你想让它可移植。答案 2 :(得分:1)
您尚未使用FLASH_IS_BUSY
,因此预处理器不会替换错误的语法。
顺便说一句,小心在旧的C标准(和更新的C ++标准)中编写while(1);
,因为程序的行为是未定义的。