当前位置:首页 > 单片机 > typedef
[导读]有个粉丝关于条件编译的问题,程序一直编译报错。我整理了关键的部分,下面代码是头文件中的定义。

粉丝问答

有个粉丝关于条件编译的问题,程序一直编译报错。我整理了关键的部分,下面代码是头文件中的定义。

#ifdef EXTERN  #undef EXTERN #define EXTERN #else #define EXTERN extern #endif EXTERN int a;

报错的内容就是error: unknown type name 'EXTERN,报错的地方是EXTERN int a;

分析

乍一看条件编译好像并没有什么不妥,但编译器确实已经报错了,那就只能说确实没有定义?。

首先,用户的意图是想用宏EXTERN代替关键字extern。

针对此模块,要保证EXTERN就是extern,所以需要判断外部是否已经定义了EXTERN。如果已经定义了,则需要取消宏定义后再重新定义。

那这里又有同学问了,如果外部已经定义了EXTERN,为什么还要取消宏定义再重新定义呢,直接用不可以吗?

严格来说是不行的,假设外部有个地方定义了

#define EXTERN const 

那么此时EXTERN就不再是extern了,意义完全变了。这时候又有同学说了,怎么可能会有人把EXTERN定义成const呢,我只能说,我也希望不会出现这种情况吧...

如果外部没有定义EXTERN会进入else分支,则在本模块直接定义。

看起来都是这么合情合理。

查看预编译文件

上面已经分析了一次,逻辑上好像没问题(指出问题了我还这么继续写下文)。既然分析没有问题,那我们直接去看预处理文件吧,简单写个Demo,头文件不变。

gcc生成预编译命令为gcc -E .\main.c -o main.i参数E代表预编译处理,o代表输出,后面跟一个文件名。代表将源文件预编译处理将处理的结果输出到main.i文件中。

内部定义EXTERN

假设我们在源文件包含头文件之前已经定义了EXTERN,如下:

#include #define EXTERN extern #include"main.h" 

然后对源文件预编译处理并截取关键信息:

# 10 ".\\main.h" int a;
# 4 ".\\main.c" 2 

未定义EXTERN

源文件部分代码,此时没有定义EXTERN。

#include #include"main.h" 

同样对源文件预编译处理并截取关键信息:

# 10 ".\\main.h" extern int a;
# 4 ".\\main.c" 2 

对比

当外部定义了EXTERN时,头文件预编译的结果没有对变量a做extern声明。外部定义了EXTERN时,头文件预编译的结果对变量a做了extern声明。

结果

宏的本质是代码替换,上述对比表明,当外部定义了EXTERN时,在处理EXTERN int a;前EXTERN变成了一个空宏。

那我们再回头看看头文件中的条件编译,如果外部定义了EXTERN则取消宏定义,并重新定义EXTERN,但是在重新定义宏的时候,这里仅仅是定义了EXTERN。并没有指明EXTERN是extern。所以编译总是提示unknown type name 'EXTERN

问题2-宏的处理顺序

问题已经找出来了,但是粉丝现在又有了新的疑问,同一个宏在多个文件是如何处理的?

其实上面的两种测试代码已经能够表明了,因为预编译也是按照先后顺序依次处理的,所以宏的处理过程也是按照先后顺序。这也是我为什么在包含main头文件之前定义EXTERN,而不是在包含头文件之后定义EXTERN

延伸问题-宏判断

发现有些同学对于一些宏的判断有些分不清楚,不清楚应该在何种场合使用。在此仍然以EXTERN为例吧。

第一种

#define EXTERN 

依稀记得当时刚毕业出来工作,当我第一次看到代码有这种定义的时候,也是挺懵逼的。甚至怀疑是不是写错了?因为我当时认为后面少了数字。为什么是少数字呢,因为在我的印象中宏都是下面这种使用方法。

#define VALUE (100) 

第一种方式宏定义仅仅代表定义了这个标识符,而不用关心它具体是什么。

常用的就是在调试模式下定义DEBUG,发布程序的时候将DEBUG关闭。主要是用来打印一些信息,方便程序员调试用的,如下:

#ifdef DEBUG //打印信息 #endif 

第二种

#if EXTERN 

注意这种使用方法,是一个判断语句,跟我们编程用if判断逻辑相同,也就是EXTERN不为0才能成立。

这种用法通常都是在定义宏时直接定义成1,例如:

#define EXTERN (1) 

第三种

#ifdef EXTERN 

这种方式和第二种有区别,这种判断只关注有没有定义,但凡你定义了,不管是什么牛马蛇神,条件都是成立的。

最后

关于宏相关的知识点,之前写过一篇文章。有兴趣的可以看看。

C语言中宏定义的盲区

这篇文章主要也是宏相关的,主要是实际编程中的问题。条件编译报错,可以去查看预处理文件,反向分析。如果你对C理解得比较深,可能一眼就能看出问题所在了。

每个人都是从小白过来的,需要时间慢慢沉淀,慢慢也就好了,加油~

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭