关于C#:在没有“extern”关键字的头文件中声明变量是否有任何缺点?

Are there any drawbacks to declaring variables in header files without the “extern” keyword?

本问题已经有最佳答案,请猛点这里访问。

我最近开始意识到,"extern"关键字的使用受到了极大的鼓励。因此,我开始怀疑当前(无外部)使用头文件的方式是否有任何问题:

主要内容:

1
2
3
4
5
6
7
8
9
#include"main.h"
#include"function.h"

int main(void){
    globalvariable = 0;

    testfunction();
    return 0;
}

H.

1
2
3
4
5
6
#ifndef MAIN_H_
#define MAIN_H_

int globalvariable;

#endif /* MAIN_H_ */

C函数:

1
2
3
4
5
6
7
#include"main.h"
#include"function.h"

void testfunction(){
    globalvariable++;
    return;
}

函数:

1
2
3
4
5
6
#ifndef FUNCTION_H_
#define FUNCTION_H_

void testfunction(void);

#endif /* FUNCTION_H_ */

因此,每个需要访问globalvariable的新源文件只需要包含main.h。

此方法的一个明显缺点是数组:声明数组后,不能使用element0、element1,…格式将值分配给数组。

顺便问一下,当我给globalvariable一个初始值为零时,我是否定义了它?或者内存分配更早?

另外,我使用的方法有官方术语吗?


对于您使用的方法,我知道的唯一官方术语是"依赖于实现的行为"。一旦开始使用不同的编译器(甚至可能是同一个编译器的不同版本)进行构建,该方法就会遇到各种各样的问题。有些人会抛出一个链接器错误,但有些人会接受它(尽管没有确切的保证如何解释它)。我强烈建议您采用一种更标准的方法,编译器将以可预测的方式进行解释。

变量的定义必须在.c文件中。如果要从另一个.c文件访问该变量,请在头中添加一个extern声明。此技术是标准C,将在任何符合要求的编译器上进行可预见的解释。

要回答您的分配问题,在程序开始运行之前,将为所有全局分配内存。全局变量占用空间,即使它只用于从不运行的代码的一部分。你的globalvariable = 0;行实际上并没有给变量一个初始值。C编译器将确保所有未初始化的全局变量在程序加载时自动初始化为零。您的代码在技术上重新分配变量的值。如果要确保全局初始化为特定值,请将初始值设定项添加到定义中,如int globalvariable = 42;


1
extern int globalvariable;

是一个声明

1
int globalvariable;

是一个声明和一个暂定的定义。

在C语言中,同一个变量有多个定义是非法的,如果在包含在多个翻译单元中的头文件中使用后者,就会发生这种情况。

然而,UNIX系统历史上允许这种用法,所以大多数编译器将接受代码,尽管它是无效的C。


问题在于,当您试图链接程序时,可能会由于多个定义而导致链接错误。您取决于这里实现定义的行为——允许实现将重复定义视为所有引用单个对象的定义,但不需要这样做。


您的代码的缺点是,您可能会遇到链接器错误。1

>1。其中"可能"是基于在一组不同的工具链上构建代码的概念。


ANSI C标准规定

If the declaration of an identifier for an object has file scope and
no storage-class specifier, its linkage is external.