Lov*_*ure 4 c language-design extern
在 C 中,默认情况下,变量和函数都在文件范围内具有外部链接。为什么extern仅变量需要关键字,而其他地方定义的函数不需要关键字?请注意,这个问题有两个方面。鉴于文件范围内的声明默认为外部链接:
extern或没有的区别?或者说,为什么客观上不需要这样的区分?extern?或者说,客观上为什么需要这样的区分?作为一个最小的示例,让我们使用以下两个源文件(tu代表“翻译单元”)。
tu1.c:
extern int i = 123;
Run Code Online (Sandbox Code Playgroud)
tu2.c:
#include <stdio.h>
extern int i;
int main(void) {
//extern int i;
++i;
printf("%d\n", i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我们可以用 GCC 编译它们,如下所示:
gcc -c tu1.c
gcc -c tu2.c
gcc -o myprogram tu1.o tu2.o
Run Code Online (Sandbox Code Playgroud)
'i' initialized and declared 'extern'(GCC对第一个命令发出警告,因为它错误地认为extern“应该保留用于非定义声明”。我们可以安全地忽略它。)
让我们比较一下编译器对于略有不同的源代码版本的行为:
extern int i;在文件范围内tu2.c(对上述代码没有更改):ismyprogram124extern int i;in main(而不是在文件范围内) in tu2.c:extern. 声明变量”)。i不在任何地方声明tu2.c:i++;我们得到以下错误:'i' undeclared (first use in this function)。int i;没有externat 文件范围tu2.c:multiple definition of `i'。我想知道最后一种情况的基本原理:如果裸露(extern-less)int i;默认为外部链接,为什么我们需要显式提供关键字extern?答案似乎在标准中(C99:6.9.2 外部对象定义),根据该标准,这int i;是一个暂定定义,在编译时实例化为实际定义。逻辑是,提供extern关键字指示编译器将生成的构造视为声明,而不是定义。但如果是这样的话:为什么同样的逻辑对于函数原型不成立,众所周知,函数extern原型是隐式的?
我有一种感觉,正确的答案与“C 中暂定定义背后的基本原理是什么?”的答案相关或接近。,但我想知道如果在上述方面对变量和函数进行相同的处理,具体会出现什么问题。
关于 C++有一个类似的问题, Peter Goldsborough 也有一篇相关文章。
习惯用 C++ 编程的人请注意:
const变量)和函数默认为外部链接。const全局变量默认为内部链接。因为函数声明的形式表明了它是否是定义。
没有函数体的函数声明不是定义:
void foo(void);
Run Code Online (Sandbox Code Playgroud)
带有主体的函数声明是一个定义:
void foo(void) { }
Run Code Online (Sandbox Code Playgroud)
有了int x;,就有歧义了。早期的 C 实现以不同的方式处理这个问题。我们可以通过给出初始化器将其标记为明确的定义:
int x = 0;
Run Code Online (Sandbox Code Playgroud)
然而,仅使用int x;,一些 C 实现将其视为一种定义(并且可能允许将多个此类定义合并为一个,因此出现在多个翻译单元中包含的头文件中的此声明将导致链接程序中只有一个定义)。
为了消除歧义,extern不使用初始化程序会使其成为不是定义的声明。
如果我们从头开始设计 C,我们可以制定一条规则,即int x;任何函数之外都有一个声明,该声明不是定义,而是int x = 0;定义。因此,语言的当前状态并不是逻辑上的必然;而是逻辑上的必然。这是语言发展历史的结果。
(但是,这样的规则与我们在函数内部使用声明的方式形成对比。在函数内部,我们习惯于成为int x;定义。如果我们对函数外部的声明采用上述规则,我们将不得不忍受声明之间的对比内部函数与外部函数或 were 必须对函数内部的声明采用相同的规则。)
| 归档时间: |
|
| 查看次数: |
451 次 |
| 最近记录: |