Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么要定义;外部;而不是使用;外人;?_C_Include_Extern - Fatal编程技术网

C 为什么要定义;外部;而不是使用;外人;?

C 为什么要定义;外部;而不是使用;外人;?,c,include,extern,C,Include,Extern,我试图制作一个简单的lexer,我发现了这个github页面: 在他的源代码中我看到: 数据.h: 。。。 #ifndef外部_ #定义外部 #恩迪夫 外线; 外部返回; 外部文件*infle; ... 主要条款c: 。。。 #定义外部_ #包括“data.h” #未定义外部_ ... 如果我只使用extern关键字,它不起作用,但与extern一起起作用,那么有什么区别呢?

我试图制作一个简单的lexer,我发现了这个github页面: 在他的源代码中我看到:

数据.h:

。。。
#ifndef外部_
#定义外部
#恩迪夫
外线;
外部返回;
外部文件*infle;
...
主要条款c:

。。。
#定义外部_
#包括“data.h”
#未定义外部_
...
如果我只使用extern关键字,它不起作用,但与extern一起起作用,那么有什么区别呢?

告诉预处理器,无论何时只要看到它,就用零替换
extern

所以在这种情况下,
extern\uu
没有任何意义


但我打赌在其他文件中,它们不使用
#define extern
。在这种情况下,头文件中的
#define extern
被激活,因为
#ifndef extern
为true(
extern
尚未定义)。它告诉预处理器用
extern
替换
extern
。因此,在一个文件中,变量的定义没有
extern
,而在所有其他文件中,变量都有
extern
。(为什么有用?如果你知道
extern
的工作原理,你就会知道为什么)

extern
的直接功能是控制
extern
关键字是否出现在变量声明中。原则上,它也可以用来替换一些其他关键字或添加限定符,但这似乎是偶然的

在这一点上,需要注意的是,问题中提供的代码并不代表引用的GitHub项目中的代码。在GitHub上,变量声明显示在标题中,而不是
main.c
中。这直接关系到为什么这样的设施是有用的

特别是,考虑整个项目中两个备选方案的差异:

  • 项目
    #中的大多数C源文件都包含
    标题,但没有定义宏
    外部
    。在这些情况下,标题本身定义了宏
    extern\uuu
    ,以扩展到关键字
    extern
    ,从而在这些翻译单位中产生这些声明:

     extern int Line;
     extern int Putback;
     extern FILE *Infile;
    
  • 文件
    main.c
    是特殊的。它定义宏
    extern\uu
    以将其扩展为零,并将头包含在该定义的范围内。然后,标头依赖于提供的宏定义,因此,仅在该翻译单元中,生成的声明是

      int Line;
      int Putback;
      FILE *Infile;
    
前者和后者的区别在于前者是纯声明,而后者是暂定定义。这一点很重要,因为程序访问的每个具有外部链接的对象必须在一个翻译单元中定义。包含给定对象的暂定定义的翻译单元肯定包含该对象的定义(比听起来复杂一点)

总的来说,这样做的效果是相同的头可以在两个不同的角色中使用:一方面,默认情况下,声明外部对象的标识符,以便可以从其他翻译单元访问它们;另一方面,在一个选定的翻译单元中定义它们,以便它们实际存在于程序中

如果我只使用extern关键字,它不工作,但它与extern一起工作,那么区别是什么

在不提供初始值设定项的情况下声明变量
extern
,即表示该变量是在程序中的某个位置定义的,但其本身不会导致定义该变量。如果给定的变量在程序中的任何地方没有以任何其他方式声明,那么所有这些承诺都没有实现,结果行为也没有定义。通常,这将以链接失败的形式表现出来

只要我提到初始值设定项,就应该谨慎地注意,将初始值设定项写入头中的声明不是一个可行的解决方案,因为包含头的每个翻译单元都会有所有变量的定义,而整个程序中每个变量的定义不得超过一个。该行为将再次未定义。在实践中,该计划有更好的机会被接受,但它仍然是错误的

最后,我注意到使用
外部
宏的整个业务有点像黑客
,不应被视为常规。实现这一点的标准方法是,头部只需声明所有变量
extern
,并且在所选的C源文件中对每个变量都有单独的定义(不一定都在同一个文件中)。例如:


数据.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 */;

// ...
#include "data.h"

// no (additional) declarations or definitions of the variables declared in data.h

其他.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 */;

// ...
#include "data.h"

// no (additional) declarations or definitions of the variables declared in data.h


如果您想为其他编译器添加更多内容或有特殊要求,通常会这样做。然后您只需要更改一个define而不是10000个声明。定义可以,但我不明白为什么在main.c中我需要为include data.h@P_uj_u定义extern_u。只是糟糕的编码你知道define是如何工作的吗?不知道,我必须承认@user253751