extern的困惑
摘自:http://blog.csdn.net/fxjtoday/article/details/6021845
如果想明白为什么需要extern, 需要从编译和链接讨论起,
现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相透明的,也就是说,在编译时,全局变量的可见域限制在文件内部。但是到了链接阶段,要将各个文件的内容“合为一体”,因此,如果某些文件中定义的全局变量名相同的话,会报错. 因此,各个文件中定义的全局变量名不可相同。
//A.cpp
int i;
void main()
{
}
//B.cpp
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的困惑的更多相关文章
- [C]关于extern与struct
问题 我曾经很困惑,就是在两个编译单元当中,如何把一个单元中声明的struct结构引入到另外一个单元中来,折腾了很久,后来发现这位大神的留言 不是这么用的…… 类型的定义和类型变量的定义不同,类型定义 ...
- 关于extern "C"(详细剖析)
[目录] 引言 extern “C”的前世今生 小心门后的未知世界 Q&A c++调用c的方法 c调用c++的方法 在你工作过的系统里,不知能否看到类似下面的代码. 这好像没有什么问题,你应该 ...
- const,static,extern 简介
const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...
- const extern static 终极指南
const extern static 终极指南 不管是从事哪种语言的开发工作,const extern static 这三个关键字的用法和原理都是我们必须明白的.本文将对此做出非常详细的讲解. co ...
- C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解
前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解 ...
- 16-static和extern关键字2-对变量的作用
上一讲介绍了static和extern对函数的作用,static用来定义一个内部函数,不允许其他文件访问:extern用来定义和声明一个外部函数,允许其他文件访问.static和extern对变量也有 ...
- 15-static和extern关键字1-对函数的作用
一.extern与函数 如果一个程序中有多个源文件(.c),编译成功会生成对应的多个目标文件(.obj),这些目标文件还不能单独运行,因为这些目标文件之间可能会有关联,比如a.obj可能会调用c.ob ...
- C#进阶系列——WebApi 接口参数不再困惑:传参详解
前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...
- 转:C++项目中的extern "C" {}
引言 在用C++的项目源码中,经常会不可避免的会看到下面的代码: #ifdef __cplusplus extern "C" { #endif /*...*/ #ifdef __c ...
随机推荐
- UIBezierPath 贝塞尔曲线
1. UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(30, 30, 100, 100) corner ...
- ACM2033
/**人见人爱A+B Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Su ...
- Trail: JDBC(TM) Database Access(1)
package com.oracle.tutorial.jdbc; import java.sql.BatchUpdateException; import java.sql.Connection; ...
- NodeJS:树的反序列化
!!不知问啥,cnblog的MarkDown编辑器不好使了. 本文也在我的博客edwardesire.com上,欢迎品尝. 树的反序列化就是将序列数组安装线索组成树结构,今次项目数据库存储决策节点的方 ...
- HDU 4791 Alice's Print Service (2013长沙现场赛,二分)
Alice's Print Service Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- 做XH2.54杜邦线材料-导线
好多市场上买的杜邦线质量一般,今天选了一种别的线 线色:红 黑 黄 绿 白 棕 蓝 线规:正标UL1007-24AWG 产品说明: * UL1007电子连接线 * 线号:24 ...
- Spring Data JPA教程, 第七部分: Pagination(未翻译)
The previous part of my Spring Data JPA tutorialdescribed how you can sort query results with Spring ...
- (转)HTML5实战与剖析之触摸事件(touchstart、touchmove和touchend)
HTML5中新添加了很多事件,但是由于他们的兼容问题不是很理想,应用实战性不是太强,所以在这里基本省略,咱们只分享应用广泛兼容不错的事件,日后随着兼容情况提升以后再陆续添加分享.今天为大家介绍的事件主 ...
- status pending状态
开发采用ssh,注解的方式,事物也application.xml配置了,但是在业务层没有使用@Transactional造成浏览器一直处于status pending状态,为什么没有使用@Transa ...
- Java二维码登录流程实现(包含短地址生成,含部分代码)
近年来,二维码的使用越来越风生水起,笔者最近手头也遇到了一个需要使用二维码扫码登录网站的活,所以研究了一下这一套机制,并用代码实现了整个流程,接下来就和大家聊聊二维码登录及的那些事儿. 二维码原理 二 ...