先看看前两篇博客:个人对头文件的理解对声明和定义的理解 

  static 函数只在定义该static函数的cpp中可见,在其他cpp中是不可见的。

  举个例子,我建立了一个project,该project中有三个文件,一个头文件,和两个cpp文件。文件内容如下:

  在build该project时会出错,错误提示是fun()函数声明了却未定义。

  为什么编译器没有找到fun()函数的定义呢?我明明在Source.cpp中定义了fun()函数呀。

  原因很简单:static函数的作用域很小只在本cpp中有效而非在整个project中都有效。所以在main.cpp中无法找到fun()函数的定义。

  根据此特性,我们可以进行一些看似行不通的操作,比如下面这个:

  咦,居然build成功了,这是为啥?我之前明明说过每个函数至多只能定义一次,这儿明明定义了“两次”。

  我们先来看看最后输出的结果是啥?是“hello“还是”world“?

  答案是“world“,即main()函数中所使用的fun()函数采用的是在main.cpp中fun()函数的定义。

  根据刚才的结论,由于static函数的作用域只在本cpp中,因此Source.cpp和main.cpp中的fun()函数的作用域并没有冲突。之前所说的函数至多只能被定义一次,实际上完整的说法应该是:在同一个作用域下,函数至多被定义一次。道理正如:一个世界上不存在两片相同的树叶,但是在另一个平行世界中,却可能存在着和我们世界相同的树叶。(要想知道根本原因的话还是得看看csapp里面关于link的这部分内容)。

  main.cpp中为fun()函数找到的定义自然是main.cpp中fun()的定义,而非Source.cpp中fun()函数的定义,因此,最后输出为“world“就可以解释的通了。

  下面讨论两种情况

  一、若是将static函数的完整定义写在头文件中会怎么样?结果是每个包含该头文件的cpp都可以使用该函数的定义。

  二、若是将非static函数的完整定义写在头文件中会怎么样?结果是:若有多个cpp文件包含该头文件,在link时,会因该函数被重复定义而失败。

那么static函数的真正用法是啥?

先说说头文件的作用:头文件的作用实际上就是声明接口(函数),包含该头文件的cpp(用户)可以调用头文件中所声明的接口(函数)。

前面说过,static函数的定义只在定义该函数的cpp中有效。下面讨论两种情况:

  第一种情况:某 static fun()函数在a.h中被声明,然后a.cpp包含了a.h并对static fun()函数作出了定义。此时有一个b.cpp出现了,它也包含了a.h,然后它就看到了fun()函数,它以为fun()函数是别人已经写好的接口,然后它就调用fun()函数,结果会如何?link失败,情况与上面的例子相同。因此static函数的声明不应该放在头文件中。

  第二种情况:将static函数的定义放在头文件中,build会出问题么?不会,但是有必要这么做么?没必要。这样做的效果是让每个包含该头文件的cpp文件都能够使用该接口(函数),既然目的是让每个cpp文件都能够使用该接口,就没必要将该函数设置为static函数了。将其设置为非static函数,在某个头文件中声明,然后随便在某个cpp文件中定义不是更好么?如果将static函数定义在头文件中,会增加compile的工作量,因为每个包含该头文件的cpp文件都需要对该函数进行编译。因此static的定义不应该放在头文件中。

  那么只剩下一种选择:static函数的声明和定义都放在cpp文件中。

使用static函数的正确姿势:

  其实static函数的真正作用在于数据隐藏(类似与c++类中的private属性),因为它只在定义它的cpp文件中是可见的嘛。

  比如说有这么一种情况,库的制作者向用户提供了两个接口interface1()和interface2(),这两个函数都调用了interfaceBase()这个函数,但是制作者并不想将interfaceBase()展示给用户(可能是怕用户用interfaceBase()函数搞破坏吧),同时interfaceBase()这个函数又只在定义这两个函数的cpp文件中使用。那么应该怎样做呢?

  首先肯定应该将interface1()和interface2()的声明放在某头文件中,为了提供接口嘛,然后在定义这两个个接口的cpp文件中定义一个static属性的interfaceBase()函数。最终如图所示:

  但是我将一个非static函数的声明和定义都放在cpp文件中也能够达到隐藏接口的目的呀,那么使用static函数有什么优势呢?

  这又得从作用域说起了,普通函数的作用域是整个project,而static函数的作用域仅限于本cpp。如果你在两个cpp文件中都定义了fun()函数,那么肯定会产生link错误。但是你如果在两个cpp文件中定义的是static fun()函数,那么就能避免link错误。

  因此使用static函数可以使函数重名。

  综上:如果某个函数只在某个cpp中使用,并且不希望将这个函数暴露给外界,那么就应该将它定义为static函数,定义在cpp中。

对c语言中static函数的理解的更多相关文章

  1. c语言中static 函数和普通函数的区别

    C程序一直由下列部分组成: 1)正文段——CPU执行的机器指令部分:一个程序只有一个副本:只读,防止程序由于意外事故而修改自身指令: 2)初始化数据段(数据段)——在程序中所有赋了初值的全局变量,存放 ...

  2. C语言中malloc函数的理解

    在C语言中malloc函数主要是用在堆内存的申请上,使用malloc函数时,函数会返回一个void *类型的值,这个值就是你申请的堆内存的首地址:为什么返回的地址是一个void *类型的地址呢?首先我 ...

  3. C语言中static的作用及C语言中使用静态函数有何好处

    转自:http://www.jb51.net/article/74830.htm 在C语言中,static的作用有三条:一是隐藏功能,二是保持持久性功能,三是默认初始化为0. 在C语言中,static ...

  4. (转)C语言中Exit函数的使用

    C语言中Exit函数的使用 exit() 结束当前进程/当前程序/,在整个程序中,只要调用 exit ,就结束return() 是当前函数返回,当然如果是在主函数main, 自然也就结束当前进程了,如 ...

  5. C语言中static的使用方法【转】

    本文转自:http://blog.csdn.net/renren900207/article/details/21609649 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量 ...

  6. C语言中static用法介绍

    C语言中static用法介绍     对于新手来说,很多东西的用法还不是很清楚,我们今天一起来看看C语言中static用法介绍     1.声明了static的变量称为静态变量,根据作用域的不同又分为 ...

  7. C语言中qsort函数用法

    C语言中qsort函数用法-示例分析    本文实例汇总介绍了C语言中qsort函数用法,包括针对各种数据类型参数的排序,非常具有实用价值非常具有实用价值. 分享给大家供大家参考.C语言中的qsort ...

  8. C语言中system()函数的用法总结(转)

    system()函数功能强大,很多人用却对它的原理知之甚少先看linux版system函数的源码: #include <sys/types.h> #include <sys/wait ...

  9. 使用C语言中qsort()函数对浮点型数组无法成功排序的问题

    一 写在开头 1.1 本节内容 本节主要内容是有关C语言中qsort()函数的探讨. 二 问题和相应解决方法 qsort()是C标准库中的一个通用的排序函数.它既能对整型数据进行排序也能对浮点型数据进 ...

随机推荐

  1. JAVA读取yml配置文件指定key下的所有内容

    先引入需要的依赖 <!--读取yml文件--> <dependency> <groupId>org.yaml</groupId> <artifac ...

  2. vue传值(父子传值,非父子传值)

    vue组件传值,分为父子传值和非父子传值,父子传值又分为父传子和子传父. 组件之间的传值,实现了数据的联动,是从操作Dom到操作数据一个跳转性的突破,在学习vue双向绑定原理之后, 这种观念就应该继续 ...

  3. 解决elment 动态多选框组(el-checkbox-group)无法设置默认值问题

    <el-checkbox-group v-model="form.showProperty"> <el-checkbox v-for="(item,id ...

  4. 【 Tomcat 】tomcat8.0 基本参数调优配置-----(1)

    Tomcat 的缺省配置是不能稳定长期运行的,也就是不适合生产环境,它会死机,让你不断重新启动,甚至在午夜时分唤醒你.对于操作系统优化来说,是尽可能的增大可使用的内存容量.提高CPU 的频率,保证文件 ...

  5. Logback源码分析

    在日常开发中经常通过打印日志记录程序执行的步骤或者排查问题,如下代码类似很多,但是,它是如何执行的呢? package chapters; import org.slf4j.Logger; impor ...

  6. ugui制作伸缩菜单

    制作一个类似与这种格式的菜单,可以伸缩滑动的.今天正好项目需要用到类似功能,所以尝试了一下,做出如下的效果 虽然只是一个思路,但是可以扩展.声明一个object物体,为but,通过GetCompone ...

  7. selenium,统计某分支下有多少个同类子分支的方法(用于循环获取同类型子分支属性值)

    利用selenium自动化统计微博阅读数 查看微博阅读数的元素路径 微博列表中第一条微博的元素路径“//*[@id="Pl_Official_MyProfileFeed__20"] ...

  8. java进阶视频分享

    更多资源和教程请关注公众号:非科班的科班. 如果觉得我写的还可以请给个赞,谢谢大家,你的鼓励是我创作的动力 课程目录介绍 01.开班仪式02.并发编程专题之多线程基础03.并发编程专题之Java内存模 ...

  9. JS-05-元素获取

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. Nginx-Http服务器常用配置

    #运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...