摘自:http://blog.csdn.net/fxjtoday/article/details/6021845

  如果想明白为什么需要extern, 需要从编译和链接讨论起,

  现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部。但是到了链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,会报错. 因此,各个文件中定义的全局变量名不可相同。

  1. //A.cpp
  2. int i;
  3. void main()
  4. {
  5. }
  6. //B.cpp
  7. int i;

  所以上面两个文件编译是没有问题的, 但是到了链接就会报重名错误

  如果此时A.cpp里面要用到, B.cpp中定义的i, 应该怎么办?

  那么既然上面说了重复定义出错, 那就把A.cpp中的"int i;"定义直接去掉是否可以

  看起来好像可以的, 因为全局变量的作用域是整个源程序, 这边也许是很多人会产生疑问的地方, 既然全局变量和全局函数的作用域是整个源程序的, 为什么在其他的文件里面使用一定要先声明(这样的声明往往在.h文件中, 并在使用处include该.h, 记住include就是copy, 之所以要使用.h, 而不是直接写在.c中, 只是为了保证易维护性, 最终编译器会自动将.h copy到每个.c中)

  答案就在编译阶段, 过程是先编译后链接, 而在编译时只能知道本文件的内容, 编译器并不能预见到你这个变量或函数在其他文件里面被定义过. 只有到了链接阶段编译器产能看到其他的文件.

  所以如果不事先声明, 那么在编译阶段一定会报错找不到该变量或函数.此时就需要使用extern来声明变量。

  extern的原理很简单,就是告诉编译器:“你现在编译的文件中,有一个标识符虽然没有在本文件中定义,但是它是在别的文件中定义的全局变量,你要放行!”

  多说一句, 在声明变量是必须要加extern, 而在声明函数时却不需要, 为什么

  上面说了, 声明只是简单的告诉编译器, 这个东西在其他地方定义过了, 你不用管了, 所以编译器不会为声明分配空间, 或做其他操作, 这和定义是有本质区别的, 必须要正确区分

  对于变量必须用extern才能区分定义和声明, 因为这是变量定义和声明的唯一区别

  而函数不需要extern也能区分处定义和声明, 有实现就是定义, 没有就是声明, 所以不需要再加extern

  这就是c的简洁之处, 不需要的就别写

  再多说一句, 在c中, 全局变量和函数都是默认对外可见的, 如果想变成仅当前文件可见, 必须加上static.

  对于函数, 默认和加上extern是等价的, 都是表示对外可见

  但是对于变量, 却不一样, 加上extern就变成声明了, 所以不能给定义加上extern

  所以对于extern有如下说法,

  用于变量,声明该变量在其它地方定义;
  用于函数定义, 表示全局可见(属于冗余的)

extern的困惑的更多相关文章

  1. [C]关于extern与struct

    问题 我曾经很困惑,就是在两个编译单元当中,如何把一个单元中声明的struct结构引入到另外一个单元中来,折腾了很久,后来发现这位大神的留言 不是这么用的…… 类型的定义和类型变量的定义不同,类型定义 ...

  2. 关于extern "C"(详细剖析)

    [目录] 引言 extern “C”的前世今生 小心门后的未知世界 Q&A c++调用c的方法 c调用c++的方法 在你工作过的系统里,不知能否看到类似下面的代码. 这好像没有什么问题,你应该 ...

  3. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  4. const extern static 终极指南

    const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...

  5. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  6. 16-static和extern关键字2-对变量的作用

    上一讲介绍了static和extern对函数的作用,static用来定义一个内部函数,不允许其他文件访问:extern用来定义和声明一个外部函数,允许其他文件访问.static和extern对变量也有 ...

  7. 15-static和extern关键字1-对函数的作用

    一.extern与函数 如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.ob ...

  8. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...

  9. 转:C++项目中的extern "C" {}

    引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __c ...

随机推荐

  1. 《浅析各类DDoS攻击放大技术》

    原文链接:http://www.freebuf.com/articles/network/76021.html FreeBuf曾报道过,BT种子协议家族漏洞可用作反射分布式拒绝服务攻击(DRDoS a ...

  2. 利用Spring.Net技术打造可切换的分布式缓存读写类

    利用Spring.Net技术打造可切换的Memcached分布式缓存读写类 Memcached是一个高性能的分布式内存对象缓存系统,因为工作在内存,读写速率比数据库高的不是一般的多,和Radis一样具 ...

  3. 更换Oracle备份数据文件

    应用背景:需要查看和修改一下Interlib中的数据,所以要反复的将备份数据进行导入和清空.整理一下步骤 删除tablespace drop tablespace interlib including ...

  4. Hibernate之管理session与批处理

    1. Hibernate 自身提供了三种管理Session对象的方法 –Session对象的生命周期与本地线程绑定 –Session 对象的生命周期与JTA事务绑定 –Hibernate 委托程序管理 ...

  5. PC问题-该虚拟机似乎正在使用中

    问题现象:运行VMware Workstation,选中一个虚拟机,运行.卡住了,再运行VMware Workstation时,选中一个虚拟机,提示“该虚拟机似乎正在使用中”. 问题原因:因为上次非正 ...

  6. Linux递归删除文件命令

    Linux递归删除文件命令 find . -name "*.log.*" -exec ls {} \; find . -name "*.log.*" -exec ...

  7. [iOS基础控件 - 6.10.7] UIWindow

    A.UIWindow概念 1.继承UIView,是一种特殊的UIView 2.通常一个APP只有一个UIWindow 3.iOS程序启动后,创建的第一个视图就是UIWindow 4.没有UIWindo ...

  8. java tools: jstack

    SYNOPSIS jstack [ option ] pidclick here to see other detail If the given process is running on a 64 ...

  9. SQL NULL Values

    NULL代表缺失的.未知的数据.表的列值默认是NULL.如果某个表的某个列不是NOT NULL的,那么当我们插入新纪录.更新已存在的记录时,可以不用为此列赋值,这意味着那个列保存为NULL值. NUL ...

  10. 视频: 千重浪Linux系统调试技术培训 03-01_Basic-CPU-Register

    免费轻松学习Linux系统调试技术 欢迎收看本工作室放到优酷上播放的免费教学视频. 清晰! 完整!  无病毒! 请点击:http://v.youku.com/v_show/id_XNjM1OTQ3Mj ...