




已阅读5页,还剩1页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
c与c+ static函数的区别 c 与c+ static 函数的区别 static 关键字是 C, C+ 中都存在的关键字 , 它主要有三种使用方式 , 其中前两种只指在 C 语言中使用 , 第三种在 C+ 中使用 (C,C+ 中具体细微操作不尽相同 , 本文以 C+ 为准 ).(1) 局部静态变量 (2) 外部静态变量 / 函数 (3) 静态数据成员 / 成员函数 下面就这三种使用方式及注意事项分别说明 一、局部静态变量 在 C/C+ 中 , 局部变量按照存储形式可分为三种 auto, static, register ( 谭浩强 , 第 174-175 页 )与 auto 类型 ( 普通 ) 局部变量相比 , static 局部变量有三点不同 1. 存储空间分配不同 auto 类型分配在栈上 , 属于动态存储类别 , 占动态存储区空间 , 函数调用结束后自动释放 , 而 static 分配在静态存储区 , 在程序整个运行期间都不释放 . 两者之间的作用域相同 , 但生存期不同 .2. static 局部变量在所处模块在初次运行时进行初始化工作 , 且只操作一次 3. 对于局部静态变量 , 如果不赋初值 , 编译期会自动赋初值 0 或空字符 , 而 auto 类型的初值是不确定的 . ( 对于 C+ 中的 class 对象例外 , class 的对象实例如果不初始化 , 则会自动调用默认构造函数 , 不管是否是 static 类型 )特点 : static 局部变量的”记忆性”与生存期的”全局性” 所谓”记忆性”是指在两次函数调用时 , 在第二次调用进入时 , 能保持第一次调用退出时的值 . 示例程序一 #include using namespace std;void staticLocalVar()static int a = 0; / 运行期时初始化一次 , 下次再调用时 , 不进行初始化工作 couta=aendl;+a;int main()staticLocalVar(); / 第一次调用 , 输出 a=0staticLocalVar(); / 第二次调用 , 记忆了第一次退出时的值 , 输出 a=1return 0;应用 :利用”记忆性” , 记录函数调用的次数 ( 示例程序一 )利用生存期的”全局性” , 改善” return a pointer / reference to a local object ”的问题 . Local object 的问题在于退出函数 , 生存期即结束 ,. 利用 static 的作用 , 延长变量的生存期 .示例程序二 :/ IP address to string format/ Used in Ethernet Frame and IP Header analysisconst char * IpToStr(UINT32 IpAddr)static char strBuff16; / static 局部变量 , 用于返回地址有效 const unsigned char *pChIP = (const unsigned char *)&IpAddr;sprintf(strBuff, %u.%u.%u.%u, pChIP0, pChIP1, pChIP2, pChIP3);return strBuff;注意事项 :1. “记忆性” , 程序运行很重要的一点就是可重复性 , 而 static 变量的”记忆性”破坏了这种可重复性 , 造成不同时刻至运行的结果可能不同 .2. “生存期”全局性和唯一性 . 普通的 local 变量的存储空间分配在 stack 上 , 因此每次调用函数时 , 分配的空间都可能不一样 , 而 static 具有全局唯一性的特点 , 每次调用时 , 都指向同一块内存 , 这就造成一个很重要的问题 - 不可重入性 !这样在多线程程序设计或递归程序设计中 , 要特别注意这个问题 .( 不可重入性的例子可以参见 ( 影印版 ) 第 103-105 页 )下面针对示例程序二 , 分析在多线程情况下的不安全性 .( 为方便描述 , 标上行号 ) const char * IpToStr(UINT32 IpAddr) static char strBuff16; / static 局部变量 , 用于返回地址有效 const unsigned char *pChIP = (const unsigned char *)&IpAddr; sprintf(strBuff, %u.%u.%u.%u, pChIP0, pChIP1, pChIP2, pChIP3); return strBuff; 假 设现在有两个线程 A,B 运行期间都需要调用 IpToStr() 函数 , 将 32 位的 IP 地址转换成点分 10 进制的字符串形式 . 现 A 先获得执行机会 , 执行 IpToStr(), 传入的参数是 0x0B090A0A, 顺序执行完应该返回的指针存储区内容是 : ” 10.10.9 .11 ” , 现执行到时 , 失去执行权 , 调度到 B 线程执行 , B 线程传入的参数是 0xA8A8A8C0, 执行至 , 静态存储区的内容是 192.168.168.168. 当再调度到 A 执行时 , 从继续执行 , 由于 strBuff 的全局唯一性 , 内容已经被 B 线程冲掉 , 此时返回的将是 192.168.168.168 字符串 , 不再是 10.10.9.11 字符串 .二、外部静态变量函数 在 C 中 static 有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。但为了限制全局变量 / 函数的作用域 , 函数或变量前加 static 使得函数成为静态函数。但此处“ static ”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件 ( 所以又称内部函数 ) 。注意此时 , 对于外部 ( 全局 ) 变量 , 不论是否有 static 限制 , 它的存储区域都是在静态存储区 , 生存期都是全局的 . 此时的 static 只是起作用域限制作用 , 限定作用域在本模块 ( 文件 ) 内部 .使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。 示例程序三 :/file1.cppstatic int varA;int varB;extern void funA() static void fun() /file2.cppextern int varB; / 使用 file1.cpp 中定义的全局变量 extern int varA; / 错误 ! varA 是 static 类型 , 无法在其他文件中使用 extern void funA(); / 使用 file1.cpp 中定义的函数 extern void fun(); / 错误 ! 无法使用 file1.cpp 文件中 static 函数 三、静态数据成员成员函数 (C+ 特有 )C+ + 重用了这个关键字,并赋予它与前面不同的第三种含义:表示属于一个类而不是属于此类的任何特定对象的变量和函数 . 这是与普通成员函数的最大区别 , 也是其应用所在 , 比如在对某一个类的对象进行计数时 , 计数生成多少个类的实例 , 就可以用到静态数据成员 . 在这里面 , static 既不是限定作用域的 , 也不是扩展生存期的作用 , 而是指示变量 / 函数在此类中的唯一性 . 这也是”属于一个类而不是属于此类的任何特定对象的变量和函数”的含义 . 因为它是对整个类来说是唯一的 , 因此不可能属于某一个实例对象的 . ( 针对静态数据成员而言 , 成员函数不管是否是 static, 在内存中只有一个副本 , 普通成员函数调用时 , 需要传入 this 指针 , static 成员函数调用时 , 没有 this 指针 . )请看示例程序四 ( 影印版 ) 第 59 页 )class Enemy Target public:Enemy Target() +numTargets; Enemy Target(const Enemy Target&) +numTargets; Enemy Target() -numTargets; static size_t numberOfTargets() return numTargets; bool destroy(); / returns success of attempt to destroy Enemy Target objectprivate:static size_t numTargets; / object counter;/ class statics must be defined outside the class;/ initialization is to 0 by defaultsize_t EnemyTarget:numTargets;在这个例子中 , 静态数据成员 numTargets 就是用来计数产生的对象个数的 .另外 , 在设计类的多线程操作时 , 由于 POSIX 库下的线程函数 pthread_create() 要求是全局的 , 普通成员函数无法直接做为线程函数 , 可以考虑用 Static 成员函数做线程函数 . /其他网络来源/今天刚开始看深度探索C+对象模型,刚看到第一章,竟然发现自己对类静态成员和静态成员函数还不够了解。查看了C+ Primer后,有以下几点体会:(1)为什么需要类静态成员?有时候某个类的多个对象需要访问一个全局对象,在这种情况下“提供一个全局对象”比“每个类都维持一个独立的数据成员”要更为有效。而类静态成员与全局变量相比,又有两点好处:(a)不存在与程序中其他全局名字冲突的可能性;(b)可设置为private,实现信息隐藏。(2)类静态成员的特点对于非静态数据成员,每个类对象都有自己的拷贝,而静态数据成员对每个类类型只有一个拷贝。由于静态数据成员分配在全局数据区,因此在程序开始运行时就必须存在,故静态数据成员的空间分配和初始化不可能在main函数或其他函数中完成(因而在局部类中也不允许出现静态数据成员)。这样一来,静态数据成员的空间分配和初始化只可能有以下三种途径:(a)类的头文件:这里有类的声明。但存在一个无法回避的问题:对于静态数据成员,在程序中也只能存在一个定义,而类的头文件可能被重复引用而出现重复定义;(b)main函数前的全局数据声明和定义处:这种方法也有问题,每一个使用该类的程序都必须在此处定义一下该类的静态成员,这是不现实的;(c)类定义的内部实现:这是最为理想的方式,引用时只需包含头文件即可。#include account.hdouble Account:_interestRate = 0.05(3)类静态成员的定义在对静态数据成员进行定义时有以下几点注意事项:(a)在类定义之外定义时,静态成员的名字必须被其类名限定修饰,前不可再添加static;(b)像int等有序类型的静态数据成员可在类定义中初始化,但仍需在类定义外进行定义,但此时已不能指定初始值;/ 头文件class Account/ .private:static const int nameSize = 16;static const char namenameSize;/ 文本文件const int Account:nameSize; / 必需的成员定义,此处不可再进行初始化const char
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 餐饮店员工劳动合同及社会保险协议
- 车辆煤炭运输与智能调度系统合同
- 特色餐厅转让合同:包含品牌、门店、经营许可等
- 商场物业维修协议书范本
- 节能环保彩钢活动房施工安装及安全协议
- 汽车安全保险业务合作协议书
- 《个人借款还款计划及欠条保管责任合同》
- 拆迁补偿款提取与二手房交易资金监管服务合同
- 3D打印桥台模型校验
- 国网可研编写培训
- 芬顿试剂投加量计算
- 精选《机械制图》期末考试题库388题(含答案)
- 2023年山西万家寨水务控股集团有限公司招聘笔试题库及答案解析
- 数码照片档案管理夏2014
- GB/T 19249-2003反渗透水处理设备
- 2023年德阳市旌阳区广播电视台(融媒体中心)招聘笔试题库及答案解析
- 小学生职业生涯规划启蒙课件PPT
- 钻井安全操作规范
- 食用菌生产技术 大球盖菇栽培技术课件
- 花城版小学二年级音乐(下)全册教案
- 小班语言课《水果歌》PPT
评论
0/150
提交评论