【问题标题】:Confusion regarding extern with function definitions in C [duplicate]关于 extern 与 C 中的函数定义的混淆 [重复]
【发布时间】:2013-02-03 11:47:48
【问题描述】:

可能重复:
Effects of the `extern` keyword on C functions

好的,几个小时以来,我已经阅读了很多关于 extern 关键字含义的内容。还有最后一件事困扰着我,我找不到任何信息。 据我了解,extern 关键字基本上告诉编译器变量或函数只是一个声明,它是在某个地方定义的,所以它不必担心,链接器会处理它。

并且在键入以下内容时编译器生成的警告(我使用的是 gcc 4.2.1):

extern int var = 10;

支持这一点。对于extern,这应该只是一个声明,所以它是不正确的。

但是,让我感到困惑的是在输入以下内容时没有警告或任何内容:

extern int func() {return 5;}

这是一个定义,它应该生成相同的警告,但它不会。我能在这里找到的唯一解释是定义覆盖了extern 关键字。但是,遵循该逻辑,为什么当它是变量定义时它不覆盖它?或者关键字与变量一起使用时是否有特殊含义?

如果有人向我解释这一点,我将不胜感激。谢谢!

【问题讨论】:

  • 最后一个分号困扰着我。
  • 看看this link是否有帮助。
  • 问题应该是变量的初始化问题
  • 虽然这个问题名义上是重复的,但建议的原件接受的答案质量很低。它过于冗长、不清楚、不完全准确,并且提供了不相关的误导性建议。

标签: c


【解决方案1】:

extern 关键字确实只有在与变量一起使用时才具有特殊含义。将extern 与函数原型一起使用是完全可选的:

extern void foo(int bar);

等价于

void foo(int bar);

当你声明/定义一个函数时,你有两个选择:

  1. 仅提供声明(即原型),或
  2. 提供定义,在没有原型的情况下也可用作声明。

但是,对于变量,您有三个选择:

  1. 仅提供声明,
  2. 使用默认初始化器提供定义:int var; 不带 = 10 部分,或
  3. 提供具有特定初始化程序的定义:int var = 10

由于函数只有两个选项,编译器可以在不使用extern关键字的情况下区分then。默认情况下,任何没有static 关键字的声明都被视为extern。因此,所有函数声明或定义都会忽略 extern 关键字。

但是,对于变量,需要关键字来区分#1 和#2。当您使用extern 时,它是#1;当你不使用extern 时,它是#2。当您尝试将extern 添加到#3 时,这是一个警告,因为它仍然是一个定义,而extern 将被忽略。

所有这一切都有些简化:您可以在同一个编译单元中多次提供声明,并且可以在全局范围或块范围内提供它们。有关完整的详细信息,请查看 C 标准的第 6.7.9 5 节。

【讨论】:

  • 关于对象(非变量)声明的陈述不正确。在文件范围内:int x; 是具有外部链接的对象的暂定定义,extern int x; 是具有外部链接的对象的声明,int x = 3;extern int x = 3; 都是具有外部链接的对象的定义。在块范围内:int x; 是一个没有链接的对象的定义,extern int x; 是一个有外部链接的对象的声明,int x = 3; 是一个没有链接的对象的定义,extern int x = 3; 是不允许的,由 C 2011 6.7.9 5....
  • 以上假设每个声明都是标识符第一次出现在该范围内。否则,会有并发症。例如static int x; extern int x;是允许的,后者x与前者x相同。此外,尽管一些编译器在文件范围内发出extern int x = 3; 的警告,但它在 C 2011 6.9.2 4 的示例中明确显示为有效。
  • @EricPostpischil 我编辑了答案,感谢 cmets。
【解决方案2】:

但是,按照这个逻辑,当它是一个变量定义时,为什么它不覆盖它呢?或者关键字与变量一起使用时是否有特殊含义?

变量和函数的区别在于

void foo();

是一个函数声明,但是

int i;

是一个变量定义。

如果您在多个文件中定义了变量,那么编译器将多次生成该变量的存储空间(并且很可能会出现链接器错误)。这不是函数的情况。

【讨论】:

  • 我认为extern int x = 1; 看起来既像声明又像带有初始化程序的定义时最令人困惑。
  • 在文件范围内,int i;是暂定定义,不是定义,既不会产生多次存储,也不会导致链接错误。
猜你喜欢
  • 2015-01-05
  • 2020-04-14
  • 2017-12-06
  • 1970-01-01
  • 1970-01-01
  • 2019-09-24
  • 1970-01-01
  • 1970-01-01
  • 2014-08-05
相关资源
最近更新 更多