慎用USES_CONVERSION(转自ALCAT专栏)

本文详细解析了USES_CONVERSION宏定义在ATL库中的应用,包括其功能、使用方法以及潜在的栈溢出问题。通过实例分析,阐述了如何避免因不当使用而导致的内存泄露和程序崩溃。此外,提供了安全的字符转换函数和优化使用策略。

首先,先介绍下USES_CONVERSION为何物。

USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。通俗的说,就是你用了这个宏后,就可以用一系列的字符串转换宏,有OLE到T,T到OLE,OLE到W,W到OLE等等,非常方便。或者说,这个宏会告诉编译器,在紧接的代码中我们要用ole库中代码(如ansi   到unicode   的A2W(...))的转换宏,不加USES_CONVERSION在使用A2W会出错。

要想使用这个宏,因为它是ATL库带的,所以要加上头文件 #include <atlconv.h>。


关于USES_CONVERSION的使用,下面是从网上摘来的一段话,讲的很不错。


USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。在ATL下使用要包含头文件#include "atlconv.h"

使用USES_CONVERSION一定要小心,它们从堆栈上分配内存,直到调用它的函数返回,该内存不会被释放。如果在一个循环中,这个宏被反复调用几万次,将不可避免的产生stackoverflow。

 

在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。

#include <atlconv.h>
void fn()
{
    while(true)
    {
        {
            USES_CONVERSION;
            DoSomething(A2W("SomeString"));
        }
    }
}

让我们来分析以上的转换宏

#define A2W(lpa) (\
   ((_lpa = lpa) == NULL) ? NULL : (\
      _convert = (lstrlenA(_lpa)+1),\
      ATLA2WHELPER((LPWSTR) alloca(_convert*2), _lpa, _convert)))

#define ATLA2WHELPER AtlA2WHelper

inline LPWSTR WINAPI AtlA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars, UINT acp)
{
   ATLASSERT(lpa != NULL);
   ATLASSERT(lpw != NULL);
   // verify that no illegal character present
   // since lpw was allocated based on the size of lpa
   // don't worry about the number of chars
   lpw[0] = '\0';
   MultiByteToWideChar(acp, 0, lpa, -1, lpw, nChars);
   return lpw;
}

关键的地方在 alloca  内存分配内存上。
#define alloca  _alloca

_alloca
Allocates memory on the stack.

Remarks
_alloca allocates size bytes from the program stack. The allocated space is automatically freed when the calling function

exits. Therefore, do not pass the pointer value returned by _alloca as an argument to free.

问题就在这里,分配的内存是在函数的栈中分配的。而VC编译器默认的栈内存空间是2M。当在一个函数中循环调用它时就会不断的分配栈中的内存。

以上问题的解决办法:
1、自己写字符转换函数,不要偷懒
Function that safely converts a 'WCHAR' String to 'LPSTR':
char* ConvertLPWSTRToLPSTR (LPWSTR lpwszStrIn)
{
  LPSTR pszOut = NULL;
  if (lpwszStrIn != NULL)
  {
 int nInputStrLen = wcslen (lpwszStrIn);

 // Double NULL Termination
 int nOutputStrLen = WideCharToMultiByte (CP_ACP, 0, lpwszStrIn, nInputStrLen, NULL, 0, 0, 0) + 2;
 pszOut = new char [nOutputStrLen];

 if (pszOut)
 {
   memset (pszOut, 0x00, nOutputStrLen);
   WideCharToMultiByte(CP_ACP, 0, lpwszStrIn, nInputStrLen, pszOut, nOutputStrLen, 0, 0);
 }
  }
  return pszOut;
}
等等一个一个的实现。

2、把字符转换部分放到一个函数中处理。

void fn2()
{
    USES_CONVERSION;
    DoSomething(A2W("SomeString"));
}

void fn()
{
    while(true)
    {
        fn2();
    }
}

如果不知道这点问题,在使用后崩溃时很难查出崩溃原因的。

USES_CONVERSION 是 ATL(Active Template Library)中的一个宏定义,主要用于支持编码换操作。在使用该宏时,需要包含特定的头文件,并且需要注意其使用场景以避免潜在的问题。 为了使用 USES_CONVERSION 宏以及相关的字符串换宏(如 A2W、W2A 等),必须包含以下头文件: ```cpp #include "atlconv.h" ``` 这个头文件提供了必要的定义和宏支持,使得在 ATL 项目中进行 ANSI 和 Unicode 字符串之间的换成为可能[^1]。 在实际代码中,USES_CONVERSION 的使用通常如下所示: ```cpp #include <atlconv.h> void fn() { while (true) { { USES_CONVERSION; DoSomething(A2W("SomeString")); } } } ``` 通过调用 USES_CONVERSION 宏,可以确保后续的字符串换宏(如 A2W)能够正常工作[^2]。 然而,在使用 USES_CONVERSION 时需要注意一些事项: 1. **栈空间限制**:ATL 换宏使用栈作为临时存储空间,直到调用它的函数返回前,这部分内存不会被释放。因此,在频繁调用换宏的情况下(例如在一个循环体内多次调用),可能会导致栈溢出(stack overflow)。 2. **适用于短字符串**:只适合进行短字符串的换,因为栈空间是有限的(VC 默认为 2MB)。 3. **避免大文件内容换**:不要尝试对大型文件内容进行换,因为这可能导致栈空间耗尽。 4. **替代方案**:对于大量数据或循环体内的换需求,建议使用 Windows API 函数 MultiByteToWideChar 和 WideCharToMultiByte 进行换,而不是依赖 ATL 的换宏[^3]。 如果需要在一个函数中多次进行字符串换,可以考虑将这些换操作封装到独立的函数中,这样每次调用都会有一个新的栈空间用于存储换结果,从而避免栈溢出问题。 总之,虽然 USES_CONVERSION 提供了方便的字符串换功能,但在使用时仍需谨慎,特别是当涉及到频繁的换操作或大数据量处理时,应当采取适当的措施来防止潜在的问题。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值