﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Just Do it!</title><link>http://www.cppblog.com/systemthink/</link><description /><language>zh-cn</language><lastBuildDate>Tue, 09 Jun 2026 18:49:04 GMT</lastBuildDate><pubDate>Tue, 09 Jun 2026 18:49:04 GMT</pubDate><ttl>60</ttl><item><title>static用法小结</title><link>http://www.cppblog.com/systemthink/archive/2008/04/08/46484.html</link><dc:creator>systemthink</dc:creator><author>systemthink</author><pubDate>Tue, 08 Apr 2008 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/systemthink/archive/2008/04/08/46484.html</guid><wfw:comment>http://www.cppblog.com/systemthink/comments/46484.html</wfw:comment><comments>http://www.cppblog.com/systemthink/archive/2008/04/08/46484.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/systemthink/comments/commentRss/46484.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/systemthink/services/trackbacks/46484.html</trackback:ping><description><![CDATA[<p><font color=#0000ff>static关键字是C, C++中都存在的关键字, 它主要有三种使用方式, 其中前两种只指在C语言中使用, 第三种在C++中使用(C,C++中具体细微操作不尽相同, 本文以C++为准).<br>(1)局部静态变量<br>(2)外部静态变量/函数<br>(3)静态数据成员/成员函数<br>下面就这三种使用方式及注意事项分别说明</font></p>
<p><font color=#0000ff>一、局部静态变量<br>在C/C++中, 局部变量按照存储形式可分为三种auto, static, register<br>(&lt;C语言程序设计(第二版)&gt;谭浩强, 第174-175页)<br>与auto类型(普通)局部变量相比, static局部变量有三点不同<br>1. 存储空间分配不同<br>auto类型分配在栈上, 属于动态存储类别, 占动态存储区空间, 函数调用结束后自动释放, 而static分配在静态存储区, 在程序整个运行期间都不释放. 两者之间的作用域相同, 但生存期不同.<br>2. static局部变量在所处模块在初次运行时进行初始化工作, 且只操作一次<br>3. 对于局部静态变量, 如果不赋初值, 编译期会自动赋初值0或空字符, 而auto类型的初值是不确定的. (对于C++中的class对象例外, class的对象实例如果不初始化, 则会自动调用默认构造函数, 不管是否是static类型)</font></p>
<p><font color=#0000ff>特点: static局部变量的&#8221;记忆性&#8221;与生存期的&#8221;全局性&#8221;<br>所谓&#8221;记忆性&#8221;是指在两次函数调用时, 在第二次调用进入时, 能保持第一次调用退出时的值. <br>示例程序一<br>#include &lt;iostream&gt;</font></p>
<p><font color=#0000ff>using namespace std;</font></p>
<p><font color=#0000ff>void staticLocalVar()<br>{<br>&nbsp;static int a = 0; // 运行期时初始化一次, 下次再调用时, 不进行初始化工作<br>&nbsp;cout&lt;&lt;"a="&lt;&lt;a&lt;&lt;endl;<br>&nbsp;++a;<br>}</font></p>
<p><font color=#0000ff>int main()<br>{<br>&nbsp;staticLocalVar(); // 第一次调用, 输出a=0<br>&nbsp;staticLocalVar(); // 第二次调用, 记忆了第一次退出时的值, 输出a=1<br>&nbsp;return 0;<br>}</font></p>
<p><font color=#0000ff>应用:<br>&nbsp;利用&#8221;记忆性&#8221;, 记录函数调用的次数(示例程序一)<br>&nbsp;&nbsp; 利用生存期的&#8221;全局性&#8221;, 改善&#8221;return a pointer / reference to a local object&#8221;的问题. Local object的问题在于退出函数, 生存期即结束,. 利用static的作用, 延长变量的生存期.<br>示例程序二:<br>// IP address to string format<br>// Used in Ethernet Frame and IP Header analysis<br>const char * IpToStr(UINT32 IpAddr)<br>{<br>&nbsp;static char strBuff[16]; // static局部变量, 用于返回地址有效<br>&nbsp;const unsigned char *pChIP = (const unsigned char *)&amp;IpAddr;<br>&nbsp;sprintf(strBuff, "%u.%u.%u.%u",&nbsp; pChIP[0], pChIP[1], pChIP[2], pChIP[3]);<br>&nbsp;return strBuff;<br>}</font></p>
<p><font color=#0000ff>注意事项:<br>1. &#8220;记忆性&#8221;, 程序运行很重要的一点就是可重复性, 而static变量的&#8221;记忆性&#8221;破坏了这种可重复性, 造成不同时刻至运行的结果可能不同.<br>2. &#8220;生存期&#8221;全局性和唯一性. 普通的local变量的存储空间分配在stack上, 因此每次调用函数时, 分配的空间都可能不一样, 而static具有全局唯一性的特点, 每次调用时, 都指向同一块内存, 这就造成一个很重要的问题 ---- 不可重入性!!!<br>这样在多线程程序设计或递归程序设计中, 要特别注意这个问题.<br>(不可重入性的例子可以参见&lt;effective C++ (2nd)&gt;(影印版)第103-105页)<br>下面针对示例程序二, 分析在多线程情况下的不安全性.(为方便描述, 标上行号)<br>① const char * IpToStr(UINT32 IpAddr)<br>② {<br>③&nbsp; static char strBuff[16]; // static局部变量, 用于返回地址有效<br>④&nbsp; const unsigned char *pChIP = (const unsigned char *)&amp;IpAddr;<br>⑤&nbsp; sprintf(strBuff, "%u.%u.%u.%u",&nbsp; pChIP[0], pChIP[1], pChIP[2], pChIP[3]);<br>⑥&nbsp; return strBuff;<br>⑦ }<br>假设现在有两个线程A,B运行期间都需要调用IpToStr()函数, 将32位的IP地址转换成点分10进制的字符串形式. 现A先获得执行机会, 执行IpToStr(), 传入的参数是0x0B090A0A, 顺序执行完应该返回的指针存储区内容是:&#8221;10.10.9.11&#8221;, 现执行到⑥时, 失去执行权, 调度到B线程执行, B线程传入的参数是0xA8A8A8C0, 执行至⑦, 静态存储区的内容是192.168.168.168. 当再调度到A执行时, 从⑥继续执行, 由于strBuff的全局唯一性, 内容已经被B线程冲掉, 此时返回的将是192.168.168.168字符串, 不再是10.10.9.11字符串.</font></p>
<p><font color=#0000ff>二、外部静态变量／函数<br>在C中static有了第二种含义：用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处&#8220;static&#8221;的含义不是指存储方式，而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.<br>使用内部函数的好处是：不同的人编写不同的函数时，不用担心自己定义的函数，是否会与其它文件中的函数同名。<br>示例程序三:<br>&nbsp;<br>//file1.cpp</font></p>
<p><font color=#0000ff>static int varA;<br>int varB;<br>extern void funA()<br>{<br>&#8230;&#8230;<br>}</font></p>
<p><font color=#0000ff>static void funB()<br>{<br>&#8230;&#8230;<br>}</font></p>
<p><font color=#0000ff>//file2.cpp</font></p>
<p><font color=#0000ff>extern int varB; // 使用file1.cpp中定义的全局变量<br>extern int varA; // 错误! varA是static类型, 无法在其他文件中使用<br>extern vod funA(); // 使用file1.cpp中定义的函数<br>extern void funB(); // 错误! 无法使用file1.cpp文件中static函数</font></p>
<p><font color=#0000ff></font>&nbsp;</p>
<p><font color=#0000ff>三、静态数据成员／成员函数(C++特有)<br>C++重用了这个关键字，并赋予它与前面不同的第三种含义：表示属于一个类而不是属于此类的任何特定对象的变量和函数. 这是与普通成员函数的最大区别, 也是其应用所在, 比如在对某一个类的对象进行计数时, 计数生成多少个类的实例, 就可以用到静态数据成员. 在这里面, static既不是限定作用域的, 也不是扩展生存期的作用, 而是指示变量/函数在此类中的唯一性. 这也是&#8221;属于一个类而不是属于此类的任何特定对象的变量和函数&#8221;的含义. 因为它是对整个类来说是唯一的, 因此不可能属于某一个实例对象的. (针对静态数据成员而言, 成员函数不管是否是static, 在内存中只有一个副本, 普通成员函数调用时, 需要传入this指针, static成员函数调用时, 没有this指针. )<br>请看示例程序四(&lt;effective c++ (2nd)&gt;(影印版)第59页)<br>class EnemyTarget {<br>public:<br>&nbsp; EnemyTarget() { ++numTargets; }<br>&nbsp; EnemyTarget(const EnemyTarget&amp;) { ++numTargets; }<br>&nbsp; ~EnemyTarget() { --numTargets; }<br>&nbsp; static size_t numberOfTargets() { return numTargets; }<br>&nbsp; bool destroy();&nbsp;&nbsp; // returns success of attempt to destroy EnemyTarget object<br>private:<br>&nbsp; static size_t numTargets;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // object counter<br>};<br>// class statics must be defined outside the class;<br>// initialization is to 0 by default<br>size_t EnemyTarget::numTargets;</font></p>
<p><font color=#0000ff>在这个例子中, 静态数据成员numTargets就是用来计数产生的对象个数的.<br>另外, 在设计类的多线程操作时, 由于POSIX库下的线程函数pthread_create()要求是全局的, 普通成员函数无法直接做为线程函数, 可以考虑用Static成员函数做线程函数.</font></p>
<font color=#0000ff></font>
<p><font color=#0000ff></font>&nbsp;</p>
<p><font face=宋体 color=#ff00ff size=4>其实正如前面我引用的一篇文章中说的那样，static有两个作用：</font></p>
<p><font face=宋体 color=#ff00ff size=4>1.限制变量和函数的作用域；</font></p>
<p><font face=宋体 color=#ff00ff size=4>2.限制变量的存储域。</font></p>
<img src ="http://www.cppblog.com/systemthink/aggbug/46484.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/systemthink/" target="_blank">systemthink</a> 2008-04-08 09:56 <a href="http://www.cppblog.com/systemthink/archive/2008/04/08/46484.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>