新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 别踩static的地雷 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 4487 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 别踩static的地雷 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     dspfirmware 帅哥哟,离线,有人找我吗?
      
      
      等级:大一(高数修炼中)
      文章:4
      积分:163
      门派:XML.ORG.CN
      注册:2006/8/9

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给dspfirmware发送一个短消息 把dspfirmware加入好友 查看dspfirmware的个人资料 搜索dspfirmware在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看dspfirmware的博客楼主
    发贴心情 别踩static的地雷

    来源于http://blog.sina.com.cn/u/1244756857:
    只要做过项目的朋友对关键字static应该都有一些了解,但未见了解很全面的。在C语言中,关键字static有以下明显的作用:
    1.static变量分配到静态内存中,这一点和全局非静态变量相同。
    2.在函数体,static变量只要不进行修改操作,在被调用过程中其值将保持不变。
    3.在模块内,全局static变量可以被模块内所有函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量,具有私有特点。
    4.在模块内,一个static函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用,也具有私有特点。

      下面来举个例子来说明static在实际应用可能会遇到问题。
      如果要求实现下面的接口:为每个大小约1600字节的音视频裸数据(audio/video)添加包头(packet header),然后将打过包头的整个数据包发送到网络。打过包头的数据包格式如下:
                         <------packet----->
                         | header | data |

      我想有人可能会这么做:

    #define MAX_PACKET_SIZE 1600

    typedef struct _header
    {
      bool type;  /*数据包类型*/
      bool length; /*数据包类型*/
     ...
    }header;

    bool send(bool type,uint8* data,uint32 length)
    {
      uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};/*定义数组*/
      header* pheader=(header*)packet;

      if(NULL==data || length<1)
      {
        return FALSE;
      }

     /*设置包头*/
      pheader->type=type;
      pheader->length=length;

      pheader++;
      memcpy((uint8*)pheader,data,length);/*拷贝数据到包头之后*/
      netSend(packet);/*将包发送到网络*/
      return TRUE;
    }
      
      对于上面的代码,有人可能会有这样的疑虑,发送数据包到网络是一个非常频繁的操作,所以在send函数中,频繁地为packet分配栈内存是一种低效的做法。他可能会将上的代码修改为:
    bool send(bool type,uint8* data,uint32 length)
    {
      uint8* packet=NULL;
      header* pheader=NULL;

      if(NULL==data || length<1)
      {
        return FALSE;
      }

      packet= (uint8*)malloc(length+sizeof(header));

      if(NULL==packet)
      {
        return FALSE;
      }

      pheader=(header*)packet;
      pheader->type=type;
      pheader->length=length;
      pheader++;

      memcpy((uint8*)pheader,data,length);

      net_send(packet);/*将包发送到网络*/

      free(packet);
      packet=NULL;

      return TRUE;
    }

    使用动态内存好象可以解决上面的问题,但它没有考虑到频繁地使用malloc-free会产生大量的内存碎片。在嵌入式系统环境中,一般内存大小有限,所以这种做法最终会导致分配失败。对于处理大流量数据问题,一种比较常用的高效方法就是在函数内部使用静态数组(全局静态数组在这个应用中不建议使用,因为全局变量会增加函数间的耦合度)。嘿嘿,听到这样的建议,估计有人会马上这么改:
    bool send(bool type,uint8* data,uint32 length)
    {
      static uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};
      header* pheader=(header*)packet;

      if(NULL==data || length<1)
      {
        return FALSE;
      }

      pheader->type=type;
      pheader->length=length;
      pheader++;

      memcpy((uint8*)pheader,data,length);
      net_send(packet);/*将包发送到网络*/
      memset(packet,0,sizeof(packet));/*清除本次内存操作*/

      return TRUE;
    }

      朋友且慢,小心地雷!

      你是否忘了考虑代码可重入(reentrance)问题呢?这里使用packet静态数组的确不用频繁地分配动态或栈内存,但同时引入了代码不可重入的问题。因为函数内的static变量分配在静态内存区,供所有对象共用。在多任务系统中,如果有一个以上的任务同时访问该内存,很可能会出现问题。所以我们必须要用其它手段来消除这个不可重入问题。使用信号量semaphore是一个很好解决不可重入问题的方法。在上面代码中加入信号量:
    bool send(bool type,uint8* data,uint32 length)
    {
      static uint8 packet[MAX_PACKET_SIZE+sizeof(header)]={0};
      header* pheader=(header*)packet;

      if(NULL==data || length<1)
      {
        return FALSE;
      }

      semTake(semaphore,WAIT_FOREVER);/*等待信号量*/

      pheader->type=type;
      pheader->length=length;
      pheader++;

      memcpy((uint8*)pheader,data,length);
      net_send(packet);/*将包发送到网络*/
      memset(packet,0,sizeof(packet));/*清除本次内存操作*/

      semGive(semaphore);/*释放信号量*/

      return TRUE;
    }

    好,现在终于解决这个问题了。在我们的视频会议系统中,曾经就在将数据发送到网络上
    踩过这个地雷,修改这个bug也化了很大功夫。

       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/8/9 8:54:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/3/28 13:05:42

    本主题贴数1,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    74.219ms