使用之前未定义的宏时没有编译器错误

时间:2015-07-06 10:44:10

标签: c compiler-errors macros preprocessor-directive

我想问你为什么在下面的代码中编译器没有给出错误? 这是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?

3 个答案:

答案 0 :(得分:3)

需要注意的是,#define在预处理阶段作为文本替换,它们与变量声明或定义不同。

在您的标头文件中,您只定义了FLASH_IS_BUSY MACRO,但在您的代码中,您还没有使用它。即使如果你已经使用过,main()之前,标题#include <msp430f5438a.h>就在那里,这使得代码可以使用FCTL3BUSY的定义,如果使用的话

TL; DR 标头文件中的FLASH_IS_BUSY定义不需要FCTL3BUSY定义。例如,您可以使用-D gcc选项提供这些MACRO值,它们根本不需要出现在代码中。

尽管如此,main()的推荐签名是int main(void)

答案 1 :(得分:2)

限制您的问题的特定主题(预处理器替换),使用:

#define FLASH_IS_BUSY (FCTL3 & BUSY)

您未以任何方式使用FCTL3BUSY。您只是指示编译器执行文本替换。它没有必要了解它们。

但是当你在代码中使用它时,这样:

int flags = FLASH_IS_BUSY;

它将执行第一次替换:

int flags = (FCTL3 & BUSY);

替换循环将继续,直到有要替换的东西(或达到硬阈值)。如果您忘记包含msp430f5438a.h,则上面的代码不会简单地编译(因为FCTL3BUSY未知),但是如果您包含了正确的头文件(没有问题的顺序) :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);,因为程序的行为是未定义的。

请参阅Is while(1); undefined behavior in C?