关于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函数的用法的更多相关文章

  1. GCC编译链接过程

    编译链接过程 代码 #cat main.c #include <stdio.h> int add(int x, int y); int sub(int x, int y); int mul ...

  2. [转]C++编译链接过程详解

    C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...

  3. C-从源文件到可执行文件的详细编译链接过程

    一直用windows一键搞定, 没有去了解详细的编译链接过程, 今天看了一篇文章, 顺便实验和记录在Linux下逐步生成的步骤. 预处理: 执行#include, #define, #if, #ifd ...

  4. 转:C语言的编译链接过程的介绍

    11:42:30 C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接 ...

  5. C++, Java和C#的编译、链接过程解析

    总是感觉java是解释性语言,转载下一篇感觉写的容易理解的文章 转自 http://www.cnblogs.com/rush/p/3155665.html 1.1.1 摘要 我们知道计算机不能直接理解 ...

  6. 【对象模型】C++模版的编译链接过程——编译器真的会检查所有tocken层面的错误么?

    模版(template)设计的初衷,是设计一种自动实例化机制,不需要使用者参与,编译器可根据使用者提供的模版参数再套用类的定义来实例化.所谓实例化,除了包含对于程序变量的实例化,即开辟空间并设置某些变 ...

  7. C/C++编译链接过程详解

    有些人写C/C++(以下假定为C++)程序,对unresolved external link或者duplicated external simbol的错误信息不知所措(因为这样的错误信息不能定位到某 ...

  8. Delphi编译/链接过程

    下面展示了Delphi是怎样编译源文件,并且把它们链接起来,最终形成可执行文件. 当Delphi编译项目(Project)时,将编译项目源文件.窗体单元和其他相关单元,在这个过程中将会发生好几件事情: ...

  9. Delphi 编译/链接过程

     

随机推荐

  1. python简单爬虫示例

    #coding=utf-8   import urllib import re   def downloadPage(url):     h = urllib.urlopen(url)     ret ...

  2. 交流从选择coding.net开始

    之前提到我们需要coding.net(一个可以帮助你在线存放管理代码的地方,便于项目合作)来进行学习交流,它可以帮我们记录我们入门的点点滴滴,现在就简单介绍一下coding.net的注册及使用. 1. ...

  3. ecshop增加新字段及相应编辑器

    一.在数据库添加字段,会手写的就后台添加,不会就进入phpmyadmin默认的就行.      这是通用的写法:(这里是增加类似商品描述的字段,其他字段自行更改) ALTER TABLE `ecs_g ...

  4. Unit04 - 继承的意义(下) 、 访问控制 、 static和final

    Unit04  -  继承的意义(下) . 访问控制 . static和final 1.方法的重写(Override):重新写.覆盖  1)发生在父子类中,方法名称相同,参数列表相同,方法体不同  2 ...

  5. php闭包实现函数的自调用,也是递归

    php的闭包可能不常用,但是在某些场合之下还是可以考虑用php的闭包来实现某些功能的,比如递归,这里讲一下用php的闭包实现递归 //php闭包实现函数的自调用,也就是实现递归 function cl ...

  6. Python开发程序:ATM+购物商城

    一.程序要求 模拟实现一个ATM + 购物商城程序 额度 15000或自定义 实现购物商城,买东西加入 购物车,调用信用卡接口结账 可以提现,手续费5% 每月22号出账单,每月10号为还款日,过期未还 ...

  7. centos7安装出现license information(license not accepted)解决办法

    若出现license information(license not accepted),即说明需要同意许可信息,输入1-回车-2-回车-c-回车-c回车,即可解决.

  8. Nginx基础整理

    目录结构如下: Nginx基础知识 Nginx HTTP服务器的特色及优点 Nginx的主要企业功能 Nginx作为web服务器的主要应用场景包括: Nginx的安装 安装环境 快速安装命令集合 各个 ...

  9. Talend 从Excel导入Saleforce数据(一) 直接从salesforce lookup 性能的噩梦

    速度的瓶颈是在查询Sales force是否有该电话号码的联系人资料. TMap属性的 lookup Model, 如果用Load Once, 则会把SaleForce的contact全部load下来 ...

  10. Win7常规快捷键

    Win7常规快捷键: Win+1:打开/显示超级任务栏第一个图标代表的程序 Win+2:打开/显示超级任务栏第二个图标代表的程序(3.4.--如此类推) Win+D:切换桌面显示窗口或者gadgets ...