原文:理解C语言中的关键字extern

最近写了一段C程序,编译时出现变量重复定义的错误,自己查看没发现错误。使用Google发现,自己对extern理解不透彻,我搜到了这篇文章,写得不错。我拙劣的翻译了一下。(原文:http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/)

  我确定这篇文章对c语言的初学者会有很大的帮助,因为这将使他们更好更熟练的使用c语言。所以就让我先来说说extern关键字在变量和函数上的应用。最基本的extern关键字扩展了变量和函数的可见度。这可能就是它为什么命名为extern的原因。

几乎所有人都知道声明和定义变量(函数)的意义,但是为了这篇文章的完整性,我想弄清楚它们。声明一个变量(函数)只是表明这个变量(函数)存在于程序的某个地方,并没有为它们分配内存。但是,声明变量(函数)具有重要作用,那就是说明变量(函数)的类型。因此,当一个变量声明,程序知道变量的类型,在函数声明的情况下,程序知道函数的参数和返回类型。这就是所谓的声明。来到定义,当我们定义一个变量(函数),除了声明的作用,它也为该变量(函数)分配内存。因此,我们可以认为声明是定义的子集。从上面的说明,显而易见,变量(函数)可以声明多次,只能定义一次。

现在回到我们的主要目标:理解C语言中的关键字extern。我已经解释过声明定义的作用了,因为我们必须借助它们来理解关键字extern。我们先来了解一种简单的情况,extern对函数的作用。默认情况下,声明和定义一个函数,都有一个extern的前缀,这意味着在声明和定义函数时,前面不写extern,它也是默认存在的。例如下面的代码。

1
int foo(int arg1, char arg2);

声明的函数前面没有extern,但编译器会在前面加上关键字extern,如下

1
extern int foo(int arg1, char arg2);

定义函数的情况和上面一样(函数的定义是指带有函数体)。因此,每当我们定义一个函数的时候,前面总会有默认的关键字extern。由于声明可以多次重复,定义只能完成一次,我们可以看到一个函数的声明可以在多个C/H文件或单个的C/H文件中重复多次。但是该函数实际只定义了一次(仅在一个文件中)。这样的函数在整个程序中都是可见的,任何文件任何地方都可以调用。(通过函数的声明,编译器在编译时就知道函数定义在哪里)。

第二种情况,extern对变量的作用。如何声明一个变量而不定义它?这是一个理解extern对变量作用的重要问题,答案如下:

1
extern int var;

在上面,一个整型变量var被声明(没有定义,没有分配内存)。并且,根据需要,我们可以声明多次。

现在,如何定义一个变量?答案如下:

1
int var;

在这里,声明及定义了一个整型变量var(声明是定义的子集,定义一个变量就包含了声明),这里还为变量var分配了内存。现在,让我们感到惊讶的是,当我们定义或声明一个函数时,前面会有默认的extern,但对于变量的情况就不一样了。如果变量也和函数一样,那么它们永远不会分配内存,它们仅仅被声明。因此,当我们想要声明而不定义一个变量就需要加上关键字extern。此外extern将变量的能见度延伸到了整个程序,我们知道变量声明和定义的地方,可以在整个程序的任何地方使用它们。下面借助几个例子来理解extern

1
2
3
4
5
6
int var;
int main(void)
{
var = 10;
return 0;
}

分析:程序编译成功,var是一个全局变量(隐势声明)

1
2
3
4
5
extern int var;
int main(void)
{
return 0;
}

分析:程序编译成功,这里var只被声明,其他地方没有使用var,所以没问题。

1
2
3
4
5
6
extern int var;
int main(void)
{
var = 10;
return 0;
}

分析:程序编译错误,由于声明了变量var,而没有在其他地方定义,从本质上讲,没有为var分配内存,程序又要给它赋值。

1
2
3
4
5
6
7
#include "somefile.h"
extern int var;
int main(void)
{
var = 10;
return 0;
}

分析:如果文件somefile.h文件中有定义变量var, 程序将会编译成功。

1
2
3
4
5
6
extern int var = 0;
int main(void)
{
var = 10;
return 0;
}

分析:猜猜上面的代码能否编译成功?在这里按照C的标准是可以编译通过的。声明一个变量并给它初始化一个值,则该变量的内存将被分配,即该变量被定义。(有的编译器会报告一个警告:warning: 'extern' variable has an initializer)

所以,我们可以得出结论:

  1. 声明可以多次,定义只能一次。

  2. 关键字extern用于扩展变量和函数的可见性。

  3. 由于函数默认存在extern,不需要再定义和声明的时候使用extern

  4. 当变量使用extern时,它只是声明没有定义。

  5. 当变量用extern声明并且有初始化时,和变量的定义一样。

【转载】理解C语言中的关键字extern的更多相关文章

  1. C语言中的关键字

    1.C语言中的关键字都有实际的意义. 2.C语言中的23个关键字如下: char:声明字符型变量. short:声明短整型变量. int:声明整型变量. long:声明长整型变量. float:声明浮 ...

  2. 理解C语言中指针的声明以及复杂声明的语法

    昨天刚把<C程序设计语言>中"指针与数组"章节读完,最终把心中的疑惑彻底解开了.如今记录下我对指针声明的理解.顺便说下怎样在C语言中创建复杂声明以及读懂复杂声明. 本文 ...

  3. 这样子来理解C语言中指针的指针

    友情提示:阅读本文前,请先参考我的之前的文章<从四个属性的角度来理解C语言的指针也许会更好理解>,若已阅读,请继续往下看. 我从4个属性的角度来总结了C语言中的指针概念.对于C语言的一个指 ...

  4. 理解C语言中几个常见修饰符

    写在前面 今天下午一个同事问「register」关键字是什么作用?噢,你说的是「register」啊,它的作用是……脑袋突然断片儿,我擦,啥意思来着,这么熟悉的陌生感.做C语言开发时间也不短了,不过好 ...

  5. C语言中的关键字总结

    1.auto 修饰局部变量,编译器默认所有局部变量都是用auto来修饰的,所以在程序中很少见到. 2.static 它作用可大了,除了可以修饰变量,还可以修饰函数,修饰变量,改变其作用域和生命周期,修 ...

  6. 2.C语言中的关键字

    1.auto 修饰局部变量,编译器默认所有局部变量都是用auto来修饰的,所以在程序中很少见到. 2.static 它作用可大了,除了可以修饰变量,还可以修饰函数,修饰变量,改变其作用域和生命周期,修 ...

  7. C 语言中的关键字 - 数据类型、数据修饰符及逻辑结构

    C 语言中有 32 个关键字.这是留个编译器用的特殊字符串,用户不可以使用. 特殊关键字 sizeof 和 return 是 C 语言中的两个特殊关键字. sizeof sizeof 用于计算变量所占 ...

  8. Python语言中的关键字(自己做的读书笔记)

    电脑配置:联想笔记本电脑 windows8系统 Python版本:2.7.8 本文章撰写时间:2015.1.1 作者:陈东陈 阅读说明: 1.本文都是先解释,后放图片: 2.文中斜体部分要么为需要输入 ...

  9. 深入理解C语言中的指针与数组之指针篇(转载)

    前言 其实很早就想要写一篇关于指针和数组的文章,毕竟可以认为这是C语言的根本所在.相信,任意一家公司如果想要考察一个人对C语言的理解,指针和数组绝对是必考的一部分. 但是之前一方面之前一直在忙各种事情 ...

随机推荐

  1. 关于teleport_pro使用过程中的一点疑惑

    在我新建工程的时候,有两个选项,一个是"new project wizard"另一个是"new project",然后就纠结了,我应该使用那个呢? 使用第一个的 ...

  2. linux系统中grub配置文件

    安装了Windows和Linux时肯定要通过GRUB进行引导,GRUB引导器的主配置文件路径/boot/grub/grub.conf(也可能是/boot/grub2/grub.conf),以#号开头的 ...

  3. Origin双坐标轴图表

    1.空白处右键Add New Colume添加新列 2.全选各个列绘制图表 3.添加新的Y轴图层Graph—New Layer—Right-Y 4.右键左上角图层2 –Layer Contents 绑 ...

  4. HTML data属性简介以及低版本浏览器兼容算法

    实例 使用 data-* 属性来嵌入自定义数据: <ul> <li data-animal-type="bird">Owl</li> <l ...

  5. 161130、Dubbo+SpringMVC工程创建详解

    Dubbo出现的目的是为了应对现在高并发,高数据量请求的问题.目前的垂直应用架构已经无法满足现在大数据的冲击,SOA就应运而生,而Dubbo在国内使用的还是比较多,稳定性也比较不错. 架构 节点角色说 ...

  6. armv8(aarch64)linux内核中flush_dcache_all函数详细分析【转】

    转自:http://blog.csdn.net/qianlong4526888/article/details/12062809 版权声明:本文为博主原创文章,未经博主允许不得转载. /* *  __ ...

  7. git 上传本地文件到github

    git 上传本地文件到github 1 git config --global user.name "Your Real Name" 2 git config --global u ...

  8. java 堆栈 静态

    所以静态变量和非静态变量的区别就在于静态变量可以用来计数,而非静态变量则不行. 理解了内存,就理解了一切,就理解了各种各样的语言.所有的语言无非都是这样:局部变量分配内存永远在栈里面,new出来的东西 ...

  9. css样式(二)(伪类 | 伪元素 | 导航 | 图像拼合 | 属性选择器 )

    一.rgb值: RGBA 颜色 RGBA 颜色值得到以下浏览器的支持:IE9+.Firefox +.Chrome.Safari 以及 Opera +. RGBA 颜色值是 RGB 颜色值的扩展,带有一 ...

  10. protoful进行序列化

    Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化.它很适合做数据存储或 RPC 数据交换格式.可用于通讯协议.数据存储等领域的语言无关.平台 ...