玖叶教程网

前端编程开发入门

条件编译报错相关问题(条件编译语句)

粉丝问答

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

#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<stdio.h>
#define EXTERN extern
#include"main.h"

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

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

未定义EXTERN

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

#include<stdio.h>
#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。并没有指明EXTERNextern。所以编译总是提示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理解得比较深,可能一眼就能看出问题所在了。

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

推荐阅读

程序预处理阶段,在做什么?

C语言中宏定义的盲区

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言