实现C语言自动释放资源的方法与探讨

 
在函数退出时,实现某些子函数(例如:释放内存,关闭句柄)调用的自动化有两个好处:
1、 减少程序员劳动强度,使得代码变得更加简洁顺畅。增强代码的可读性。
2、 增强代码的健壮性。
 
在C语言中如何释放资源?我们必需把return 语句替换成如下这样:
 
#define vreturn returnfunc();    return
 
#define LIST_NAME    g_unique_exit_head_list
#define LOCAL_EXIT_INIT   PCALL_LISTLIST_NAME=NULL
#define LSET_EXIT_FUNC setexitfunc
 
typedef struct _M_MM {
         struct _M_MM * pNext ;           // 指向下一个要释放的资源节点
         DWORD   ParamSpace ;          // 资源释放函数需要的参数字节数
         LPVOID pFunc ;                // 释放资源的函数
         DWORD param [1];             // 可变长数组,存放参数
} CALL_LIST ,* PCALL_LIST ;
 
为了说明问题,下面请看一段代码
….
If((FileHandle=CreateFile(…)==0)
{
    ….
    return STATUS_ERROR;
}
….
If((pmem=VirtuallAlloc(…)==0)
{
    …
    CloseHandle(FileHandle);
    return STATUS_ERROR;
}
….
以上代码替换成如下这个样子
 
….
 
If((FileHandle=CreateFile(…)==0)
{
    ….
    vreturn STATUS_ERROR;
}
LSET_EXIT_FUNC(LIST_HEAD,1 ,CloseHandle, FileHandle );
 
….
If((pmem=VirtuallAlloc(…)==0)
{
     //CloseHandle(FileHandle); 本应在退出之前加入这句,把return换成vreturn之后就不用了。
    vreturn STATUS_ERROR;
}
LSET_EXIT_FUNC(LIST_HEAD,1 ,VirtualFree, pmem );
 
….
 
这种释放资源的方法,将在下一个产品作为一个标准的编码方法引入,以便减少退出之前忘了调用相关函数而产生的错误。这种错误一旦发生,往往出错位置比较隐蔽,在实验室当中肯定无法重现,而且需要客户配合才能解决。
 
说了这么多,不知道细心的朋友是否会注意到,因为退出的时候,需要调用不同的函数释放资源。那么肯定会面临这样一个问题:被用来释放资源的函数,可能是_stdcall函数,可能是_cdecl类型,可能有的函数需要三个参数,有的却不需要参数。
对于_stdcall类型的函数,我的实现方法如下:
 
         returnfunc()
         {
        
                  PCALL_LIST pList , pListNext ;                  
                  for ( pList = m_pList ; pList ;)                    // m_pList 链表头。
                   {
                            callapi ( pList );                                            // 调用释放资源函数
                            pListNext = pList -> pNext ;
                            delete pList ;                                               // 释放链表本身
                            pList = pListNext ;
                   }
     }
         void callapi ( PCALL_LIST pList )           // 调用释放资源函数
         {
                   BYTE * pesp ,* pnewesp ;
                  DWORD ParamSpace ;
 
                  ParamSpace = pList -> ParamSpace ;    // 释放 API 函数用到的参数字节数。参数个数 *SIZEOF(DWORD)
                   _asm mov pesp ,esp;                                      //
                   pesp -= ParamSpace ;                                 // 把参数拷贝到当前 ESP 所指的位置
                  pnewesp = pesp ;                         // 为了下一步调用的函数,设置参数
                  memcpy ( pesp , pList -> param , ParamSpace );    //
                   pesp = ( BYTE *) pList -> pFunc ;             //
                   _asm {
                            mov eax, pesp
                            mov esp, pnewesp
                           call eax                       // 这里调用释放资源函数,因为是 _STDCALL 函数,
// 所以不需要自己填平堆栈,如果是 _cdecl 函数,
// 应该如何填平堆栈呢?因为 esp 已经变化了,
// 应该如何知道 esp 的正确位置呢??
                   }
         }
 
 
对于_cdecl类型的函数如何调用,我还没有很好的方法,如何恢复堆栈。各位高人一起想想看:)。
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值