【问题标题】:extern keyword doesn't seem to to anythingextern 关键字似乎没有任何作用
【发布时间】:2021-02-08 17:30:01
【问题描述】:

我在文件 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 关键字。

这里发生了什么?

【问题讨论】:

  • 你的“include”实际上是将b.c中的代码复制粘贴到a.c中,对代码没有逻辑影响
  • 在上面的代码中,去掉extern int a;这一行并没有什么区别,因为a的定义已经在作用域内,即从main可见,由于#include。但是如果你只放弃extern,这会有所作为; a 将成为 main 的本地变量,与 b.c 中定义的变量不同。

标签: c extern


【解决方案1】:

以这个程序为例:

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

这个的输出是:

10

extern 是声明,而不是定义。

它没有定义一个变量,这意味着它没有给它任何内存。它只声明了变量,所以你可以使用它。

在您的示例中,您不必声明 a,原因很简单,因为 #includes 基本上将粘贴代码复制到您的程序中。

如果你移动

#include"b.c"

在程序的底部,您需要 extern 语句,因为尚未定义 y

旁注:extern 可以是一个定义,如果它有一个等号,正如@John Bollinger 所说。不过,在您的示例中,情况并非如此。

【讨论】:

  • 但是我为什么要把它移到 main 下呢?
  • @DuarteArribas:没有理由。只是为了测试。当然,如果您有理由,那么您将需要 extern 关键字。这就是它的目的。
  • 警告:如果提供了初始化程序,extern 声明仍然是一个定义:extern int a = 1;
【解决方案2】:
  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

【讨论】:

    【解决方案3】:

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

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

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

    要按名称引用对象,您需要提供该名称的声明。您包含的int a=1; 是一个声明(它是一个定义)。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-19
      • 1970-01-01
      • 2012-05-12
      • 1970-01-01
      相关资源
      最近更新 更多