无法理解全局变量和具有外部存储 class 的变量之间的区别?

Can't understand difference between a global variable and a variable having external storage class?

我写的时候有什么区别:-

#include<stdio.h>

int a=10; 

main( )
{
     printf ("%d", a);
}  

另一个是:-

#include<stdio.h>

main ( )    
{
    extern int a=10; 
    printf ("%d", a); 
}

None 我的编译器(tcc、gcc、clang)在块范围内接受 extern int a = 10;(带有初始值设定项 (=10))。它在文件范围内是合法的,如 example from the standard:

所证明
int i1 = 1;                    // definition, external linkage
static int i2 = 2;             // definition, internal linkage
extern int i3 = 3;             // definition, external linkage
int i4;                        // tentative definition, external linkage
static int i5;                 // tentative definition, internal linkage
int   i1;                      // valid tentative definition, refers to previous
int   i2;                      // 6.2.2 renders undefined, linkage disagreement
int   i3;                      // valid tentative definition, refers to previous
int   i4;                      // valid tentative definition, refers to previous
int   i5;                      // 6.2.2 renders undefined, linkage disagreement
extern    int   i1;            // refers to previous, whose linkage is external
extern    int   i2;            // refers to previous, whose linkage is internal
extern    int   i3;            // refers to previous, whose linkage is external
extern    int   i4;            // refers to previous, whose linkage is external
extern    int   i5;            // refers to previous, whose linkage is internal

这里和int a = 10;没什么区别,但是clang和gcc都警告反对。

通常 extern 用于引用别处定义的数据对象(它是可选的函数)。将它与定义一起使用虽然合法,但并不常见。

我能想到的一个区别是重新声明变量。声明全局 a 时,可以在函数内声明另一个局部 a。编译器会使用局部变量,不会出现编译错误。

但是,使用extern int a然后重新声明int a会导致编译错误。

正如其他人所指出的,您的第二个示例无法编译。但是这个变体确实:

#include <stdio.h>

int a = 10;

int main(void) {
    extern int a;
    printf ("%d", a); 
}

既然带你去问extern storage-class说明符的作用,那我们就来说说这版代码吧

默认情况下,块作用域变量声明没有链接并声明具有自动存储持续时间的对象。这样的变量特定于最内层包含块的一次执行,不能从外部直接访问。但是,如果我们声明一个块作用域变量 extern,那么我们就是在声明在该作用域中我们正在使用具有外部链接的变量的标识符。这可能就是你所说的 "global variable".

的意思

但是块作用域 extern 声明不允许是它声明的对象的 定义。对于变量,这意味着它不能包含初始值设定项,并且它不会为此类对象保留任何存储空间。它只是声明您打算引用别处定义的对象。这在单文件示例中毫无意义,但它对于访问由不同文件提供的外部变量可能很有用,而不是让当前文件中的每个函数都可以访问它。

示例:

main.c:

#include <stdio.h>

int main(void) {
    extern int a;
    printf("%d\n", a); 
    return 0;
}

other.c

int a = 10;

如果这些单独的源文件被编译并链接在一起,那么生成的程序将具有明确定义的行为:它会在其标准输出中打印“10”,然后是一个换行符。

对于根据 C 标准的初学者,不带参数的函数 main 应声明为

int main( void ) 

这个节目

#include<stdio.h>

main ( )    
{
    extern int a=10; 
    printf ("%d", a); 
}

不正确。根据C标准(6.7.9初始化)

5 If the declaration of an identifier has block scope, and the identifier has external or internal linkage, the declaration shall have no initializer for the identifier.

但是,如果您要删除初始化程序,例如

#include<stdio.h>

main ( )    
{
    extern int a; 
    printf ("%d", a); 
}

然而,该程序将具有未定义的行为。根据 C 标准(6.9 外部定义)

5 An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier; otherwise, there shall be no more than one.

考虑到在上面的程序中标识符a有外部链接(6.2.2 标识符的链接)

4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

一个正确的程序可能看起来像下面这样

#include <stdio.h>

int main(void) 
{
    extern int a;
    printf( "a = %d\n", a );

    return 0;
}

int a = 10;

它的输出是

a = 10

在这个程序中有标识符的外部定义a与外部链接

int a = 10;