C语言中的extern

本文为译文,原文点击这里

C有一个关键字extern如:

#include <stdio.h>
int main() {
  extern int x;
  printf("x = %d\n", x);
}

主义x前面的extern,这有什么用?让我们来编译一下:

$ clang main.c 
/tmp/main-9b5b3f.o: In function `main':
main.c:(.text+0x15): undefined reference to `x'
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)

为了理解这个错误,我们需要理解externextern是一个可以应用于声明(declaration)的关键字。如:

extern int x;
extern char * errstr;

为了理解extern,我们必须首先理解声明(declaration)、定义(definition)和初始化(initialization)之间的区别。看下这个例子:

int x = 5;

上面这行代码做了三件事:

  1. 说明x存在并且类型是int;
  2. 它为x分配内存(足够一个整型数);
  3. 为该内存分配初值5。

这三部分称为声明(declaration)、定义(definition)和初始化(initialization):

  1. 变量声明(declaration):声明具有给定类型的变量的存在性;
  2. 变量定义(definition):为该变量分配内存;
  3. 变量初始化(initialization):为该内存提供一个初始值。

我们经常将声明、定义和初始化变量一起完成,如上边的例子。然而,我们不必同时做这三件事!

声明定义初始化
int x = 5;
int x;×
extern int x;××

对一个C变量来说,extern声明了该变量而没有定义它。也就是说,在程序的那个点上没有为它分配内存,必须在其他地方定义变量。
其他地方留给链接器去寻找。注意,上面clang的错误消息不是编译器错误,而是链接器错误。运行clang main.c时,先运行编译器,然后是链接器。编译成功,但是链接失败了,因为它没有找到x。我们可以使用-c标志来看编译阶段:

$ clang -c main.c
$ ls
main.c	main.o

然后,我们可以通过执行下面命令看到,链接阶段失败:

$ clang main.o
main.o: In function `main':
main.c:(.text+0x15): undefined reference to `x'
clang-6.0: error: linker command failed with exit code 1 (use -v to see invocation)

对象文件,比如main.o,有一个符号表(symbol table)。这个表描述了对象文件中定义的内容,以及对象文件期望从其他地方获得的内容。我们可以用nm工具来看这个符号表:

$ nm main.o
0000000000000000 T main
                 U printf
                 U x

T mian说在main.o中定义了一个符号(symbol)mainU printfU x是说main.o中声明但是没有定义符号printfxmain.o期望连接器去寻找printfx,clang链接器通过链接C标准库成功地找到了printf。但是,链接器在任何地方都找不到x,因此它会报错。
为了修正这个错误,我们需要在某处定义x。我们可以在一个单独的目标文件,像这样:

// x.c
int x = 5;  // define and initialize x
$ clang -c x.c
$ nm x.o
0000000000000000 D _x
$ clang main.o x.o
$ ./a.out
x = 5
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值