你能给我解释一下下面问题的流程吗?
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;输出是20。我不确定变量a是在哪里定义的,又是在哪里声明的?
发布于 2017-06-26 11:53:30
在下面的代码行中,变量a被声明并定义为全局变量:
int a = 20;extern行只是告诉main()函数作用域a是在另一个地方定义的。
在这种情况下,并不需要使用extern。您只需在main()函数之前声明和定义a,然后main()就会熟悉它。
通常,当您想要使用在另一个源文件(而不仅仅是在同一个源文件中稍后定义的)中定义的变量或函数时,可以使用extern。
发布于 2017-06-26 13:35:36
C编程语言被设计为一次通过,因此编译器从上到下只能处理每一行一次。因此,考虑到你的程序:
#include <stdio.h>
int main(){
extern int a;
printf("%d\n",a);
return 0;
}
int a = 20;标识符a声明了两次,定义了一次。
在第4行extern int a;之前,编译器对标识符a一无所知。声明extern int a;在函数main内具有块作用域,它将标识符a声明为int,并且它的存储持续时间是静态的,链接是外部的。因此,编译器可以编写代码,通过名为a的int变量来访问全局标识符,该变量可以在另一个模块(外部链接)中定义。这就是编译器在printf中使用时在行5上所做的事情。
最后在第9行,int a = 20;是另一个声明和定义。它将a声明并定义为具有静态存储持续时间和外部链接的int。
如果您将int a = 20;放在main之前,声明extern int a;将是无用的,因为它不会添加任何东西。我倾向于将我的main和其他依赖函数放在源代码的最后,这样就只需要最少的额外声明。
发布于 2017-06-26 13:33:50
extern在语法上是一个“存储类”关键字。但是没有这样的存储类。C有“静态存储”、“动态存储(malloc等)”和“自动存储”(局部变量,通常使用堆栈表示)。
如果标识符在块范围内声明为extern,则意味着该声明引用了外部定义。如果被声明的实体是一个对象,那么它就有静态存储,这很简单,因为外部对象有静态存储。它也可以是一个函数;函数不是说有存储空间。
在C中,有一个叫做“链接”的概念。在文件范围内任何函数外部声明的对象和函数,可以有“外部”或“内部”链接。
如果我们在块作用域中有extern,就像在示例程序中一样,可以在文件作用域或嵌套作用域中有相同名称的先前声明,如下所示:
static int x;
/* ... */
{
extern int x;
}在这里,内部x指的是外部x,尽管它是“外部”的,但由于“静态”,它具有内部链接。
简而言之,extern通常意味着“引用先前的声明,如果没有声明,则将其声明为具有外部链接的标识符”。
“外部”一词指的是两个不同的概念:前述的“外部联系”和“任何功能之外”的含义,如“外部声明”。令人困惑的是,“外部声明”,就像上面的static int x一样,可以有“内部链接”!
在您的程序中,事情是正确的,因为a的块作用域extern声明和后来的int a = 20处于不同的作用域中,它们恰好彼此独立地一致。
int a = 20;是一个外部声明,它也是一个外部定义(因为初始值设定项)。因为在该作用域中,先前看不到a的声明,所以它获得外部链接。
那么,a是在哪里定义的呢?它被定义为具有外部联系的对象,在整个翻译单位中作为一个整体。这个翻译单元就是定义a的单元。在程序中出现声明的每个地方都声明了a;它的定义也是一个声明。它是在main中声明的,也在翻译单元源代码的最后一行中声明。
“声明”是一种语法,它使名称在一定范围内为人所知。它是一个在程序翻译过程中活跃的概念。“定义”是在某些翻译单元中提供某些对象或功能的事实。翻译后的单元仍然提供定义,但不需要保留有关声明的信息。(这就是为什么当我们创建库时,我们提供带有声明的头文件!)
从main函数的角度来看,该函数并不“关心”a是在哪里定义的。它声明a的方式是,如果使用a,则必须存在具有外部链接的a的外部定义。这个定义可以来自任何地方:它可以在同一个翻译单元中,也可以在另一个翻译单元中。
https://stackoverflow.com/questions/44752795
复制相似问题