转:从编译链接过程解析static函数的用法
关于static函数的用法
就像我们熟知的那样,变量可以分全局的和局部的,函数也可以分全局的和局部的。
比如说,在一个工程的common.h中定义了一个全局变量 int test;那么在整个工程的作用范围内,该变量都是存在的,在编译的时候会将其保存在整个工程全局的变量表中,文件(.h或.cpp)只要使用声明extern int test;就可使用该变量,而不用包含该变量的头文件common.h,因为该变量的作用域是全局的。
和全局变量一样,大多数的非类成员函数基本上都定义为全局的。我们可以分两种情况讨论,第一种情况,void func();被声明在commom.h中,实现体在common.cpp中。这种情况和全局变量的情况一样,整个工程内的任何程序都可以通过extern voud func();来使用该函数,而不需要包含头文件common.h。当然了,还可以通过包含头文件的方式使用func();。工程内的任何文件都可以包含common.h而不会出现名字冲突问题,因为common.h中只包含了函数的声明而没有实现体,任何包含了common.h的文件因此也就只包含了函数的声明,因此编译是没有问题的。至于函数的实现体,会在链接的时候自动到对应的obj(由对应的cpp生成)文件中寻找。
当把一个全局函数的声明和实现都放在common.h中时,如果有2个以上文件都包含了common.h,在编译的时候就无法通过,因为每包含一次common.h,就会在全局空间内保存一个func()实现体(最终会保存在obj固定的全局区域),如此一来,就会有多个个func()实现体保存在全局空间中(分别保存在多个obj中,在链接的时候会整合成一个总的exe),从而导致命名冲突。所以,一般都会使用class来封装函数,可以避免很多的命名冲突问题。
还有一种方法可以避免全局函数的命名冲突,可以将函数的声明和实现都放在common.h中,但是要加上static声明,即static void func(){};加上static就表明该函数只在本文件(common.h)中可用,在包含该头文件的obj全局空间内不会保存func()的实现体,任何文件要想使用func(),只能通过包含头文件(或者说是包含该函数的作用域)的方式来使用它,不能通过extern void func();来直接使用,因为此时的func()以不在整个工程全局空间的控制范围内。
还有一种情况,如果将函数的声明放在头文件中,将函数的实现放在对应的cpp文件中,并且将实现体加上了static声明,那么此时的static没有太大作用,因为既然将函数体放在了cpp中,别人一般不会包含你的cpp文件,也就不存在命名冲突问题了,除非有几个文件非要包含你的cpp文件不可,那么此时的static就派上用场了。
其实只要对编译的过程理解了,这些问题都很容易搞懂。下面简单讲一下编译的原理。
程序写好之后会先进行编译,在编译阶段,编译器会为每个cpp文件生产一个.obj文件,该文件就保存了每个文件中的全局变量或者全局函数的标识符,如果一个文件使用了另外一个文件中的全局函数并且没有包含其头文件,在编译的时候,编译器首先会寻找是否使用了extern声明,如果找到了,此时编译器就放心了,它知道这个函数是在别的地方定义了,在链接的时候会自动找到的,所以编译器就编译通过了。
编译完之后就会对每个.obj文件进行整合链接,最终生成可执行的exe文件。在链接阶段,此时的所有相关的.obj文件都被放到了整个工程的全局空间内,链接器会检查所有的.obj文件是否存在全局变量或者函数的命名冲突问题,如果多个obj文件都包含了某个全局函数的实现体,此时编译器就会报命名冲突错误,因为每个obj包含的不是函数的声明,而是结结实实的函数体,大家都知道,函数可以被声明多次,但是函数体只能定义一次,那么此时的函数体被每个obj都定义了一次,肯定会导致命名冲突问题。
解决的办法上面也说了,只能将函数体移到cpp文件中,头文件中只包含函数的声明,由此只有该cpp文件对应的obj文件中存在函数体,那么链接的时候果断不会有问题了;或者将函数体声明为static,此时的每个obj文件中就不会有该函数的定义了,该函数在编译阶段已经被整合到obj代码中了,不会出现在obj的全局空间中,所以在链接的时候不会有问题。
链接器的作用就是将每个单独的obj文件按照代码中的依赖关系进行整合(其中就包括对全局空间变量或者函数进行整合),最终生成exe文件。
补充一下,工程中的每一个cpp文件都会生成一个对应的obj文件。 关于static基本的用法就这么多,以后如有更深入的研究再继续补充
转:从编译链接过程解析static函数的用法的更多相关文章
- GCC编译链接过程
编译链接过程 代码 #cat main.c #include <stdio.h> int add(int x, int y); int sub(int x, int y); int mul ...
- [转]C++编译链接过程详解
C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...
- C-从源文件到可执行文件的详细编译链接过程
一直用windows一键搞定, 没有去了解详细的编译链接过程, 今天看了一篇文章, 顺便实验和记录在Linux下逐步生成的步骤. 预处理: 执行#include, #define, #if, #ifd ...
- 转:C语言的编译链接过程的介绍
11:42:30 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接 ...
- C++, Java和C#的编译、链接过程解析
总是感觉java是解释性语言,转载下一篇感觉写的容易理解的文章 转自 http://www.cnblogs.com/rush/p/3155665.html 1.1.1 摘要 我们知道计算机不能直接理解 ...
- 【对象模型】C++模版的编译链接过程——编译器真的会检查所有tocken层面的错误么?
模版(template)设计的初衷,是设计一种自动实例化机制,不需要使用者参与,编译器可根据使用者提供的模版参数再套用类的定义来实例化.所谓实例化,除了包含对于程序变量的实例化,即开辟空间并设置某些变 ...
- C/C++编译链接过程详解
有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某 ...
- Delphi编译/链接过程
下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件. 当Delphi编译项目(Project)时,将编译项目源文件.窗体单元和其他相关单元,在这个过程中将会发生好几件事情: ...
- Delphi 编译/链接过程
随机推荐
- 线性探测再散列 建立HASH表
根据数据元素的关键字和哈希函数建立哈希表并初始化哈希表,用开放定址法处理冲突,按屏幕输出的功能表选择所需的功能实现用哈希表对数据元素的插入,显示,查找,删除. 初始化哈希表时把elem[MAXSIZE ...
- C++笔记----构造函数与析构函数(二)
构造函数是一种特殊的成员函数.在创建对象的时候自动调用,对对象的数据成员进行初始化. (1)栈区中创建的对象,在生存期结束的时候会自动调用析构函数. (2) 在堆上创建的对象,要由程序员显示调用del ...
- 与子域名共用session信息
参考自 http://www.jb51.net/article/19664.htm 下面的步骤只使用于两个域名在同一个服务起得情况下,如果不在一个服务器上,就需要考虑通过数据库来存储session信息 ...
- 前台 JSON对象转换成字符串 相互转换 的几种方式
在最近的工作中,使用到JSON进行数据的传递,特别是从前端传递到后台,前台可以直接采用ajax的data函数,按json格式传递,后台Request即可,但有的时候,需要传递多个参数,后台使用requ ...
- SQLServer性能调优3之索引(Index)的维护
前言 前一篇的文章介绍了通过建立索引来提高数据库的查询性能,这其实只是个开始.后续如果缺少适当的维护,你先前建立的索引甚至会成为拖累,成为数据库性能的下降的帮凶. 查找碎片 消除碎片可能是索引维护最常 ...
- synchronized同步块和volatile同步变量
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- Solr6.2.0 + zookeeper 集群配置
zookeeper1 : 192.168.1.103zookeeper2 : 192.168.1.104zookeeper3 : 192.168.1.105solr1 : 192.168.1.106s ...
- iOS,文本输入,键盘相关
1.UIKeyboard键盘相关知识点 2.点击空白区域隐藏键盘(UIKeyboard) 3.键盘(UIKeyboard)挡住输入框处理 4.自定义键盘(UIKeyboard) 5.监听键盘弹出或消失 ...
- tapping of data 词义来源
tapping of data 在数据交互的过程 数据被 窃听到. 例如, 网站的账户被泄露, 在用户登陆过程中, 其账号被第三方偷到. tapping 含义 看看 youdao 词典解释: n. [ ...
- Struts2(一):怎么创建对应版本的struts.xml
1.eclisep导航菜单:windows->preferences->Xml->Xml Catalog; 2.在Xml Catalog右侧,添加一个新的XML Catalog: 3 ...