【问题标题】:Why use the extern keyword in header in C? [duplicate]为什么在 C 的 header 中使用 extern 关键字? [复制]
【发布时间】:2013-10-12 11:49:28
【问题描述】:

为什么要在下面的代码中使用extern关键字:

header.h

float kFloat; // some say I should write 'extern float kFloat;', but why?

文件.c

#include <stdio.h>
#include "Header.h"

float kFloat = 11.0f;

main.c

#include <stdio.h>
#include "Header.h"

int main(int argc, const char * argv[])
{
    printf("The global var is %.1f\n", kFloat);

    return 0;
}

此代码有效。全局变量 kFloat 默认为外部链接和静态生命周期。

输出为:

全局变量为 11.0

我不明白在什么情况下会出现问题,谁能给我一个会崩溃的例子吗?

【问题讨论】:

    标签: c extern linkage


    【解决方案1】:
    extern float kFloat;
    

    声明 kFloat 而不定义它。

    但是:

    float kFloat;
    

    也声明了kFloat,但它是kFloat暂定定义

    添加extern 只会取消暂定定义。在头文件中你只需要声明,而不是定义。

    如果暂定定义包含在多个源文件中,您最终将拥有同一对象的多个定义,这在 C 中是未定义的行为。

    【讨论】:

    【解决方案2】:

    始终将全局变量的定义(如float kFloat;)放在.c 文件中,并将声明(如extern float kFloat;)放在标题中。

    否则当多个.c文件包含同一个header时,会出现多重定义错误。

    【讨论】:

    • 我无法重现定义错误,我不太明白你的意思。
    • @ViktorLexington 链接时发生错误,而不是编译,您是否进行了链接?
    • 我运行 main.c 代码并且输出打印没有问题,所以它们都是链接的。输出值为11.0。
    • @ViktorLexington 我明白了。所以在你的 main.c 中,你仍然有float kFloat = 11.0f; 这是暂定定义,请参阅@ouah 的回答,他对此有更好的解释。要重现多定义错误,您需要将其删除并仅在标题中包含定义。
    • @ViktorLexington 如果我理解正确,暂定定义仍然是定义,因此如果标题包含在多个文件中,您将有未定义的行为。未定义的行为意味着即使在一台机器上一切正常,在另一台机器上也可能不行。
    【解决方案3】:

    首先,奇怪的是您的代码正在编译。它应该在File.c 中对kFloat 变量的双重定义抛出编译时错误。

    其次,如果您尝试在两个文件中使用公共变量,则不应在header.h 中定义它。您应该在头文件中使用extern 关键字,以便包含header.h 的文件知道它已被外部定义。

    现在,您可以在任何 c 文件中全局定义变量,然后将该变量用作公共变量。

    【讨论】:

    • 但是头文件中的定义有默认的外部链接,所以我不需要 extern 关键字来访问变量。我使用 c11 编译器,甚至用 c99 尝试过,都没有警告。
    • @ViktorLexington:头文件中的定义是暂定的,因为它没有在那里初始化。因此它不会引发任何错误,因为它不会与任何实际定义相冲突。当 kFloat 在 file.c 中初始化时,它得到了真正的定义。所以相同的变量在 main.c 和 file.c 中都是可见的,具有相同的值。现在,特别是这种情况,在初始化头文件中的变量之前不需要 extern。但我建议在头文件中使用 extern,因为如果在任何一个 c 文件中都没有提供定义,则会出现错误。
    • 欲了解更多信息,请参阅以下帖子中的答案:stackoverflow.com/questions/8108634/…
    【解决方案4】:

    extern 表示在您要使用的项目(或外部功能块)中的某处定义了一个变量。它不会为它分配内存,因为您告诉编译器这是在其他地方定义的。

    一个变量必须在程序的一个模块中定义一次。如果没有定义或有多个定义,则会产生错误,可能在链接阶段。

    定义是指变量被创建或分配存储的地方;声明是指声明了变量的性质但没有分配存储空间的地方。

    因为它可以在其他地方访问,所以它需要是静态的。

    【讨论】:

    • 但我的变量已定义。两者都是外部链接和静态寿命。那你的意思是什么?
    【解决方案5】:

    为什么要使用 extern ...?

    嗯,你不应该。干净利落。因为你不应该使用全局变量,它们是唯一需要 extern 关键字的变量。

    每当您想使用全局变量时,请三思。在绝对最大值下,您可能需要使用具有文件范围的变量(使用 static 关键字),通常这样的变量会伴随着一些操作/使用其值的函数,但变量本身不应该是在文件范围之外可见。使用全局变量只会导致难以处理的代码,如果不引入大量错误,几乎不可能更改。

    【讨论】:

    • 一些书籍建议使用全局常量变量而不是宏,因为添加了类型信息。
    • 啊,是的,这将是extern 关键字的一种有效用法,因为这样的“变量”不是变量而是常量。但是,其他书籍不鼓励使用 const 变量,因为 C 无法像 C++ 那样消除此类变量的运行时存储。如果我不使用#define,我会使用enumstatic const 变量作为编译时间常量,而不是extern
    • 你的断言背后有一个真实的元素,但也有一个过度陈述的元素。例如,全局变量stdinstdoutstderr 比任何不使用全局变量的方案都要方便得多。我想你可以创建函数来“获取”值,但它不会是同一个世界。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 2019-01-16
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 2011-01-21
    • 2010-12-28
    相关资源
    最近更新 更多