为什么定义 "extern_" 而不是使用 "extern"?
Why define "extern_" rather than using "extern"?
我试图制作一个简单的词法分析器,我发现了这个 github 页面:https://github.com/DoctorWkt/acwj/tree/master/01_Scanner
在他的源代码中我看到了:
data.h:
...
#ifndef extern_
#define extern_ extern
#endif
extern_ int Line;
extern_ int Putback;
extern_ FILE *Infile;
...
main.c:
...
#define extern_
#include "data.h"
#undef extern_
...
如果我只使用不起作用的 extern 关键字,但它与 extern_ 一起使用,那么有什么区别?
#define extern_
告诉预处理器在看到 extern_
时什么都不替换。
所以在这种情况下 extern_
没有任何意义。
但我敢打赌他们不会使用其他文件 #define extern_
。在那种情况下,头文件中的 #define extern_ extern
被激活,因为 #ifndef extern_
为真(extern_
尚未定义)。这告诉预处理器用 extern
替换 extern_
。因此,在一个文件中,变量的定义没有 extern
,而在所有其他文件中,它们都有 extern
。 (为什么有用?如果你知道 extern
是如何工作的,你就会知道为什么)
extern_
宏的直接作用是控制extern
关键字是否出现在变量声明中。原则上,它也可以用来替代其他一些关键字或添加限定词,但这似乎是偶然的。
在这一点上,重要的是要注意问题中提供的代码并不代表所引用的 GitHub 项目中的代码。在 GitHub 上,变量声明出现在 header 中,而不是 main.c
中。这与为什么这样的设施有用直接相关。
特别是,考虑在整个项目中执行的两个备选方案之间的区别:
项目#include
中的大部分C源文件header没有定义宏extern_
。在那些情况下,header 本身定义宏 extern_
以扩展到关键字 extern
,导致这些翻译单元中的这些声明:
extern int Line;
extern int Putback;
extern FILE *Infile;
文件 main.c
比较特殊。它定义宏 extern_
以扩展为空,并且在该定义的范围内包含 header。 header 然后依赖于提供的宏定义,因此 在单独的翻译单元中 ,结果声明是
int Line;
int Putback;
FILE *Infile;
前者与后者的区别在于前者是纯粹的声明,而后者是初步定义。这很重要,因为程序访问的每个 object 和外部 linkage 必须在一个翻译单元中定义。包含给定 object 暂定定义的翻译单元肯定包含 object 的定义(这比听起来要复杂一些)。
那么,总的来说,效果就是同一个header可以用在两个不同的角色上:一方面,默认情况下,声明外部object的标识符,以便它们可以从其他翻译单元访问,另一方面可以在一个选定的翻译单元中定义它们,以便它们实际存在于程序中。
If I use just the extern keyword that dosn't work but it work with extern_ so what is the difference?
声明变量 extern
而不提供初始值设定项构成对变量在程序某处定义的承诺,但它本身 导致 变量被定义.如果给定的变量没有以任何其他方式在程序的任何地方声明,那么所有这些承诺都没有实现,并且结果行为是未定义的。通常,这将以 link 失败的形式出现。
只要我提到初始值设定项,似乎谨慎的做法是注意将初始值设定项写入 header 中的声明并不是一个可行的解决方案,因为每个包含 header 的翻译单元都会具有所有变量的定义,而在整个程序中每个变量的定义不得超过一个。该行为将再次未定义。在实践中,该程序被接受的可能性更大,但它仍然是错误的。
最后,我注意到 整个使用 extern_
宏的业务有点像 hack,不应被视为传统业务。做到这一点的规范方法是 header 简单地声明所有变量 extern
,并且在选定的 C 中每个变量都有一个 单独的 定义源文件(不一定都在同一个文件中)。示例:
data.h
extern int Line;
extern int Putback;
extern FILE *Infile;
main.c
#include "data.h"
int Line /* optionally with an initializer here */;
int Putback /* optionally with an initializer here */;
FILE *Infile /* optionally with an initializer here */;
// ...
other.c
#include "data.h"
// no (additional) declarations or definitions of the variables declared in data.h
我试图制作一个简单的词法分析器,我发现了这个 github 页面:https://github.com/DoctorWkt/acwj/tree/master/01_Scanner 在他的源代码中我看到了:
data.h:
...
#ifndef extern_
#define extern_ extern
#endif
extern_ int Line;
extern_ int Putback;
extern_ FILE *Infile;
...
main.c:
...
#define extern_
#include "data.h"
#undef extern_
...
如果我只使用不起作用的 extern 关键字,但它与 extern_ 一起使用,那么有什么区别?
#define extern_
告诉预处理器在看到 extern_
时什么都不替换。
所以在这种情况下 extern_
没有任何意义。
但我敢打赌他们不会使用其他文件 #define extern_
。在那种情况下,头文件中的 #define extern_ extern
被激活,因为 #ifndef extern_
为真(extern_
尚未定义)。这告诉预处理器用 extern
替换 extern_
。因此,在一个文件中,变量的定义没有 extern
,而在所有其他文件中,它们都有 extern
。 (为什么有用?如果你知道 extern
是如何工作的,你就会知道为什么)
extern_
宏的直接作用是控制extern
关键字是否出现在变量声明中。原则上,它也可以用来替代其他一些关键字或添加限定词,但这似乎是偶然的。
在这一点上,重要的是要注意问题中提供的代码并不代表所引用的 GitHub 项目中的代码。在 GitHub 上,变量声明出现在 header 中,而不是 main.c
中。这与为什么这样的设施有用直接相关。
特别是,考虑在整个项目中执行的两个备选方案之间的区别:
项目
#include
中的大部分C源文件header没有定义宏extern_
。在那些情况下,header 本身定义宏extern_
以扩展到关键字extern
,导致这些翻译单元中的这些声明:extern int Line; extern int Putback; extern FILE *Infile;
文件
main.c
比较特殊。它定义宏extern_
以扩展为空,并且在该定义的范围内包含 header。 header 然后依赖于提供的宏定义,因此 在单独的翻译单元中 ,结果声明是int Line; int Putback; FILE *Infile;
前者与后者的区别在于前者是纯粹的声明,而后者是初步定义。这很重要,因为程序访问的每个 object 和外部 linkage 必须在一个翻译单元中定义。包含给定 object 暂定定义的翻译单元肯定包含 object 的定义(这比听起来要复杂一些)。
那么,总的来说,效果就是同一个header可以用在两个不同的角色上:一方面,默认情况下,声明外部object的标识符,以便它们可以从其他翻译单元访问,另一方面可以在一个选定的翻译单元中定义它们,以便它们实际存在于程序中。
If I use just the extern keyword that dosn't work but it work with extern_ so what is the difference?
声明变量 extern
而不提供初始值设定项构成对变量在程序某处定义的承诺,但它本身 导致 变量被定义.如果给定的变量没有以任何其他方式在程序的任何地方声明,那么所有这些承诺都没有实现,并且结果行为是未定义的。通常,这将以 link 失败的形式出现。
只要我提到初始值设定项,似乎谨慎的做法是注意将初始值设定项写入 header 中的声明并不是一个可行的解决方案,因为每个包含 header 的翻译单元都会具有所有变量的定义,而在整个程序中每个变量的定义不得超过一个。该行为将再次未定义。在实践中,该程序被接受的可能性更大,但它仍然是错误的。
最后,我注意到 整个使用 extern_
宏的业务有点像 hack,不应被视为传统业务。做到这一点的规范方法是 header 简单地声明所有变量 extern
,并且在选定的 C 中每个变量都有一个 单独的 定义源文件(不一定都在同一个文件中)。示例:
data.h
extern int Line;
extern int Putback;
extern FILE *Infile;
main.c
#include "data.h"
int Line /* optionally with an initializer here */;
int Putback /* optionally with an initializer here */;
FILE *Infile /* optionally with an initializer here */;
// ...
other.c
#include "data.h"
// no (additional) declarations or definitions of the variables declared in data.h