C 如果全局变量有默认的外部链接,那么为什么';我们不能直接在另一个文件中访问它吗?

C 如果全局变量有默认的外部链接,那么为什么';我们不能直接在另一个文件中访问它吗?,c,global-variables,extern,C,Global Variables,Extern,我已经回答了以下问题: 上面的链接描述了,如果我们在一个文件中定义了全局变量,并且没有指定extern关键字,那么由于转换单元的原因,它们将可以在另一个源文件中访问 现在我有了file1.c,其中定义了以下全局变量和函数: int testVariable; void testFunction() { printf ("Value of testVariable %d \n", testVariable); } 在file2.c中有以下代码 void main() {

我已经回答了以下问题:

上面的链接描述了,如果我们在一个文件中定义了全局变量,并且没有指定
extern
关键字,那么由于转换单元的原因,它们将可以在另一个源文件中访问

现在我有了
file1.c
,其中定义了以下全局变量和函数:

int testVariable;

void testFunction()
{
    printf ("Value of testVariable %d \n", testVariable);
}
file2.c
中有以下代码

void main()
{
    testVariable = 40;
    testFunction();
}
现在我发现
错误:“testVariable”未声明(首次在此函数中使用)
——为什么

注意:使用makefile在同一程序中使用这两个文件

根据我的理解,函数和全局变量都有默认的外部链接。所以我们可以直接使用另一个文件中的函数名,但变量不能,为什么

有人知道吗

编辑:

从下面的答案中,我得到了一个想法,就像在函数的情况下一样,旧编译器会猜测并添加一个隐式声明,但在变量的情况下,它不能。C99还删除了隐式声明,但在C99模式下仍会收到如下警告:

warning: implicit declaration of function ‘testFunction’.
现在已经通过以下链接:

它说,编译器将其作为诊断目的,不会给出错误。所以编译器可以向前处理


但为什么变量不能进一步处理?即使在函数的情况下,若编译器继续运行,若实际定义不在那个里,那个么在链接时它也会失败。那么向前推进有什么好处呢?

当编译器处理
file2.c
时,它对
testVariable
的存在及其类型一无所知。因此,它无法生成代码来与这样的对象交互。线条的目的和意义

extern int testVariable;
就是让编译器知道这样的对象存在于某个地方,并且其类型为
int
。 对于函数,我们并没有这样的问题,因为下一条规则——若函数并没有定义——编译器假定它是在类似的地方定义的

int testFunction() { ... }

因此,您可以向它传递任意数量的参数,并尝试获取
int
返回值。但如果实际函数签名不同,您将在运行时获得未定义的行为。由于这个缺点,这种方法被认为是不好的做法,您应该在调用该函数之前声明正确的函数原型。

这里有两件事在起作用:第一,定义和声明之间存在差异。另一件事是概念

定义是定义变量的东西,它是变量存在的实际位置,编译器为变量保留空间的地方

编译器需要声明才能知道程序中的某个地方存在符号。如果没有声明,编译器将不知道符号存在

翻译单元基本上是非常简化的源文件及其包含的所有头文件。对象文件是单个翻译单元,链接器使用所有翻译单元来创建最终程序

现在,一个程序只能有一个定义,例如,一个全局变量可能只存在于一个翻译单元中,或者链接时会出现多个定义错误。另一方面,声明可以存在于任意数量的翻译单元中,编译器将使用它告诉链接器翻译引用了另一个(编译时未知)翻译单元中的定义

所以这里发生的是,您在
file1.c
中有一个定义和一个声明。此源文件用作一个翻译单元的输入,编译器为其生成一个单一的目标文件,例如
file1.o
。在另一个源文件
file2.c
中,没有全局变量
testVariable
的定义或任何声明,因此编译器不知道它存在,并将为它提供一个错误。您需要声明它,例如

extern int testVariable;  // This is a declaration of the variable
对于函数来说,这要复杂一点,因为在旧版本的C标准中,不必声明正在使用的函数,编译器会猜测并添加隐式声明。如果定义和隐式声明不匹配,将导致未定义的行为,这就是C99标准中删除隐式函数声明的原因。因此,您也应该声明函数:

void testFunction(void);  // Declare a function prototype
注意这里不需要
extern
关键字,因为编译器可以自动判断它是函数原型声明

完整的
file2.c
应该如下所示

extern int testVariable;  // This is a declaration of the variable

void testFunction(void);  // Declare a function prototype

void main()
{
    testVariable = 40;
    testFunction();
}

如果编译器假定每个未声明的变量都是
extern
对象,则永远不会收到关于缺少声明的警告。此外,编译器如何知道对象的类型?@EOF那么编译器在函数的情况下如何工作?在旧的C标准中,有隐式函数声明的概念。它已从较新的标准中删除,应该避免使用。您可能希望使用编译器选项进行编译,以使用现代C标准和警告。@如果是,我知道我们可以通过将警告视为错误来避免它。但我的问题是,为什么在变量的情况下,它直接被视为错误?当然,您可以访问它们。您只需在要访问它们的文件中声明它们。实现这一点的标准方法是将外部声明放在头文件(一个
.h
文件)中,然后将该文件包含在您想要使用它们的地方。那么,尽管我们需要在另一个文件中写入extern关键字来访问,但将默认外部链接添加到全局变量有什么好处呢?IMO没有任何好处。默认链接与在每个翻译单元中声明使用过的顶级对象的要求无关。@user2520119没有好处。当没有其他说明符时,该语言可以以一种使内部链接成为默认的方式进行定义,但我当然