Extern 关键字似乎没有做任何事情

问题描述 投票:0回答:3

我有以下程序在两个文件中:

a.c

#include<stdio.h>
#include"b.c"
int main(void){
  extern int a;
  a+=2;
  printf("%d\n",a);
  return 0;
}

b.c

int a=1;

现在我使用 extern 关键字来声明变量 a,但不定义它。 因此,我可以更改其内容,并且打印它会打印 3.

我不明白的是,如果我从 a.c 中删除

extern int a;
行,程序也会运行,并且输出仍然是 3。

我认为要更改 b.c 中的变量,必须使用 extern 关键字。

这里发生了什么?

c extern
3个回答
2
投票

以这个程序为例:

#include<stdio.h>
void main()
{
    extern int y;
    printf("%d",y);
}
int y=10;

输出如下所示:

10

extern
是一个声明,而不是(必然)一个定义。

单独使用时,

extern
不会定义变量,这意味着它不会为其分配内存地址。它只是声明变量,以便您可以使用它。

在您的示例中,您不必声明

a
,原因很简单,它已经被定义了。

另一方面,如果

extern
变量立即分配给某个东西,它也会定义它。 (谢谢,@John Bollinger

extern int b=20;

#include
指令未定义逻辑范围。

以一种简单(且正确)的理解,

#include
复制将代码从一个文件粘贴到您要运行的文件中。这意味着如果删除
extern
语句,就不会有问题,因为
a
已经由
int a=1;
定义了。将其视为通常使用全局变量。

另一方面,如果你移动

#include"b.c"

在程序的底部,您需要

extern
声明。如果没有它,编译器就不会知道
y
将在某个时刻被定义。该语句告诉编译器在发送错误告诉您变量不存在之前搜索声明。


1
投票
  1. 当您包含该文件时,编译器正在编译一个文件。

事实上你正在编译:

#include<stdio.h>
int a = 1;
int main(void){
  extern int a;
  a+=2;
  printf("%d\n",a);
  return 0;
}

您只有一个编译单元,并且

a
未在另一编译单元中定义。

当您从声明中删除

extern
时,您定义了未初始化的局部自动变量
a
。然后你使用它,它就具有不可确定的价值。它可以是任何东西。

#include<stdio.h>
int a = 5;
int main(void){
  int a;
  a+=2;
  printf("%d\n",a);
  return 0;
}

这个程序不太可能输出

7
https://godbolt.org/z/GeGvbd


0
投票

当编译器编译

main
例程时,它已经在您包含的
int a=1;
中看到了
b.c
,因此
extern int a;
不会告诉它任何新内容。因此它不会做任何事情。

extern int a;
表示“
a
int
的名称,而
int
是在其他地方定义的。”但是,通过包含
b.c
,您就包含了
int a=1;
,它定义了
a
。所以编译器已经知道
a
被定义为
int

我认为要更改 b.c 中的变量,必须使用 extern 关键字。

要按名称引用对象,您需要提供该名称的声明。您包含的

int a=1;
是一个声明(也是一个定义)。

您不需要

extern
来表示我将通过名称引用一个对象,但您确实需要它来表示“我不是在此处定义该对象,只是告诉您在某处定义的对象。”正确的使用方法不是将
b.c
包含在
a.c
中,而是:

  • b.c
    中,用
    a
    定义
    int a=1;
  • b.h
    中,用
    a
    声明
    extern int a;
  • a.c
    中,使用
    #include "b.h"
    包含声明。
  • a.c
    中,您不需要自己编写
    extern int a;
    ,因为当您包含
    b.h
    时您就会明白。
  • b.c
    中,使用
    #include "b.h"
    检查声明。 (当您在
    b.h
    中包含
    b.c
    时,编译器将在同一编译过程中同时看到声明和定义,如果存在导致声明冲突的错误,它会发出警告。)
© www.soinside.com 2019 - 2024. All rights reserved.