试图证明在C

时间:2017-12-01 01:36:10

标签: c extern

我想了解外部。根据其中一个最佳答案 How to correctly use the extern keyword in C

这是为了解决头文件的多个包含的问题,导致同一变量的多个副本,从而导致链接错误。

所以我通过创建以下文件来尝试它:

count.h

int count;

count.c

int count = 0;

add.h

int sum(int x, int y);

add.c

#include "count.h"
int sum(int x, int y){
count = count + 1;
return x+y;}

sub.h

int sub(int x, int y);

sub.c

#include "count.h"
int sub(int x, int y){
count = count + 1;
return x - y;
}

的main.c

#include "count.h"
#include "add.h"
#include "sub.h"
#include <stdio.h>

int main(){
  printf("%d\n", count);
  printf("%d\n", sub(100,1));
  printf("%d\n", count);
  printf("%d\n", add(100,1));
  printf("%d\n", count);
}

使用输出编译并运行良好:

0
99
1
101
2

我在原始的count.h文件中使用或不使用extern获得相同的输出。那么答案中我错过了什么?

现在,我认为答案是“我只是声明多个计数副本”,因为没有标题保护,这是好的,因为多个声明都可以,而多个定义则没有。 但是如果是这样的话,我希望编译以下内容,但是因为我“重新定义计数”所以没有。

int main(){
   int count;
   int count; 
   int count = 0;
}

根据这个答案,int count算作一个定义。 In C, is it valid to declare a variable multiple times?

2 个答案:

答案 0 :(得分:2)

第二种情况的不同之处在于您在函数中的同一范围中多次声明count。如果你这样做了:

int count;
int count; 
int count = 0;

int main(){
    return 0;
}

你会没事的。这样做的原因是因为没有初始值设定项的声明是暂定定义

来自C standard

的第6.9.2节
  

2 具有没有初始化程序且没有存储类的文件范围的对象的标识符声明   说明符或存储类说明符static构成一个   暂定定义。如果翻译单元包含一个或多个   标识符和翻译单元的暂定定义   不包含该标识符的外部定义,然后是   行为就像翻译单元包含一个   具有复合类型的该标识符的文件范围声明   截至翻译单元的末尾,初始化程序等于0。

     

...

     

4 示例1

int i1 = 1;         //    definition, external linkage
static int i2 = 2;  //    definition, internal linkage
extern int i3 = 3;  //    definition, external linkage
int i4;             //    tentative definition, external linkage
static int i5;      //    tentative definition, internal linkage
int i1;             //    valid tentative definition, refers to pre vious
int i2;             //    6.2.2 renders undefined, linkage disagreement
int i3;             //    valid tentative definition, refers to pre vious
int i4;             //    valid tentative definition, refers to pre vious
int i5;             //    6.2.2 renders undefined, linkage disagreement
extern int i1;      //    refers to previous, whose linkage is external
extern int i2;      //    refers to pre vious, whose linkage is internal
extern int i3;      //    refers to previous, whose linkage is external
extern int i4;      //    refers to previous, whose linkage is external
extern int i5;      //    refers to previous, whose linkage is internal

答案 1 :(得分:2)

你的

int count;
count.h中的

实际上是定义,而不仅仅是声明。这是暂定的定义,但是作为每个暂定的定义,它在每个包含上述内容的翻译单元的末尾生成了int count的正常完整定义。

因此,通过将count.h包含在多个翻译单元中,您在程序中生成了外部对象int count的多个定义,这在标准C中是正式非法的。它&#34;编译并运行良好& #34;只是因为许多现代C编译器实现了编译器扩展。

根据Rationale for International Standard — Programming Languages — C(参见 6.2.2标识符的链接一节),在当天的Unix编译器使用的轻松的遗留声明/定义模型中,这曾经是好的(所谓的&#34;轻松参考/ Def&#34;模型)。然而,更正式的K&amp; R C拒绝了Unix模型并将其替换为所谓的&#34; Strict Ref / Def&#34;模型,它只允许一个定义。后来,标准化委员会决定采用严格的参考/定义&#34;模型和&#34;初始化&#34;模型,仍然只允许一个定义。然而,&#34;轻松参考/ Def&#34;在旧的Unix编译器中,许多现代编译器继续支持这个模型作为扩展。

为了使您的程序符合标准C的要求,您必须从头文件中删除int count的定义,并将其替换为非定义声明

extern int count;

这使extern对变量声明有用。