C/C++宽窄字符串转换及其注意事项(一)

今天在调试公司代码的时候,因为宽窄字符串转换问题引起程序崩溃,所以,趁此机会,把最近用到的方法总结一下。 

一、ATL and MFC String Conversion Macros 

1) ATL 7.0 字符串转换类和宏  

ATL 7.0介绍了几种新的字符串转换类和宏,以下的宏有明显改善的地方。转换格式如下: 

C(源字符串)2[C](目的字符串)[EX] 

C:转换出来的目的字符串为常量

EX:初始化缓冲区时必须指定大小做为模板参数  


源字符串/目的字符串的类型:  

A:ANSI字符串 

W:Unicode字符串  

T:标准字符串(Unicode版本等价于W,Multi-Byte版本等价于A) 

OLE:OLE字符串(等价于W)  

比如,把一个Unicode字符串转为一个常量的标准字符串,用CW2CT。如果知道一个转换字符串很可能小于64个字符,如果用EX版的,如CW2CTEX<64>,常常可以节省栈空间。


注意:转换BSTR字符串推荐的方法是用CComBSTR类。若转为BSTR字符串,被转字符串要有CComBSTR构造函数。若转换BSTR字符串,用COLE2[C](目的字符串)[EX],比如COLE2T。 

新的字符串转换类(CA2AEX,CA2WEX,CW2AEX,CW2WEX)需要一个固定大小的静态buffer来存放转换结果。如果结果超出这个buffer,该类会用malloc申请内存,超出作用域的时候会释放内存。与旧版的宏比较,新的类在循环中使用时是安全的,不会溢出堆栈。 

在ATL 7.0中字符串转换宏优化了空字符串的转换。如果输入一个没有申请内存的空字符串,转换结果也是空字符串。  

默认情况下,ATL转换类和宏在转换时会使用当前线程的ANSI代码页。如果你想用其他的代码页,在使用CA2WEX或CW2AEX类时,要在构造函数的第二个参数指明代码页来覆盖默认的代码页。在使用时这些宏时,最好检查字符串的长度,避免潜在的堆栈溢出的运行时错误。可以用try/except来捕获堆栈溢出这样的异常。  

旧版的ATL 3.0字符串转换宏和新版的ATL 7.0字符串转换类有几点显著的不同之处: 

①前者是在栈上申请内存空间;后者为小的字符串在栈上申请内存空间,如果栈不够大,则在堆上申请。  

②前者在函数退出时释放内存;后者则是超出作用域释放内存。 

③前者不能在异常处理程序中使用;后者则可以在异常处理程序中使用。  

④前者不适合在循环中使用,否则在函数退出前内存一直会增长;后者可以在循环中使用,每次迭代结束就释放内存。

⑤前者不适用大的字符串转换,因为栈的范围是有限的;后者适用于比较大的字符串,超出范围则会在堆上申请内存。

⑥前者需要使用宏USES_CONVERSION;后者不需要。 

⑦OLE字符串依赖于OLE2ANSI的定义;后者OLE等价于W。  

在字符串转换宏的名字中,源字符串类型在左边,目的字符串类型在右边。A代表LPSTR类型,OLE代表LPOLESTR类型,T代表LPTSTR类型,W代表LPWSTR类型。如果有C在宏名里面,转换结果是一个常量。如W2CA是将一个LPWSTR字符串转换成一个LPCSTR字符串。ATL字符串转换取决于编译器指令。

如果目的字符串类型不是BSTR的,创建目的字符串用_alloca,用_alloca在栈上申请内存,所以当函数返回时,会自动清理。默认情况下,使用这些宏会一次性向上申请500KB的空间。在使用ATL字符串转换宏前,在函数开始先使用宏USES_CONVERSION ,避免编译错误。如:

void StringFunc(LPSTR lpsz)

{  

USES_CONVERSION;  

LPWSTR x = A2W(lpsz);  

// Do something with x  

wprintf_s(L"x is %s", x);

}  

需要的头文件是AtlBase.h, AtlConv.h ,在AtlConv.h 中声明定义这些宏。


猜你喜欢

转载自blog.csdn.net/zlanbl085321/article/details/51255241