A2W、W2A、A2T、T2A、(USES_CONVERSION)

转载 2015年07月09日 08:46:30

这儿是个关于宏的问题,我曾用过ATL的串转换宏,包括W2A,开始有些东西我还不太明白。为了使用这些宏,必须在函数的开始处用USES_CONVERSION来初始化某些局部变量。用就用吧,但是看看这个宏的定义,它有类似下面的代码:

// 在atlconv.h文件中
#define USES_CONVERSION /
int _convert; _convert; /
UINT _acp = GetACP(); _acp; /
LPCWSTR _lpw; _lpw; / 
LPCSTR _lpa; _lpa

为什么它们用“int x;x;”——这种后面跟着变量的声明? 
    很多人都碰到过这个令人困惑的问题,后来发现简单的答案是:禁止编译器的警告信息(warning)。如果单独有一行代码:
int x;
且从来没有使用过x,那么编译器汇报错“unreferenced local variable:x”,意思是未引用过的局部变量x,如果将警告信息的输出调到最大。为了避免讨厌的警告,USES_CONVERSION引用声明的变量。

int x; // 声明
x; // 使用这个变量

在C++之前的时代,程序员有时在C中用函数形参做同样的事情来避免“unreferenced formal parameter”或其它的深奥费解的编译错误。

这儿是个关于宏的问题,我曾用过ATL的串转换宏,包括W2A,开始有些东西我还不太明白。为了使用这些宏,必须在函数的开始处用USES_CONVERSION来初始化某些局部变量。用就用吧,但是看看这个宏的定义,它有类似下面的代码:

void MyFunc(int x, char y)
{
x;
y;
…
}
当然,现在用下面的代码可以更有效地完成同样的事情:

void MyFunc(int /* x */) 
{
…
}

也就是说声明参数,但不给它起名,不能这样使用局部变量;必须显式地引用它。这样做不会增加任何指令到代码中。最多可能多增加几个字节到堆栈(为x预留空间)。灵巧的编译器甚至不会操心x从来没有被使用过——虽然好奇心可能想知道:如果编译器够厉害,知道了从没有使用x,为什么要抱怨(编译出错)呢?答案是因为苛刻的程序员(且编程能力与个人的记性有关)使用编译警告提醒自己删除某部分代码时发生变量荒废。这种警告在C时代很有用,你必须在每个函数的顶部声明变量,这就远离了实用它们的代码。
现在来看看另一个问题:为什么在开始位置要用USES_CONVERSION?即为什么W2A&Co之类的宏还需要另外的宏声明自己的变量;为什么不直接在W2A中声明这个变量?


#define W2A(x) /
int _convert; _convert; /
……etc

很明显这样做不行,因为如果你使用W2A两次,得到一个复制的变量。那为什么不把整个宏放进花括弧创建新的范围?

#define W2A(x) Q{ /
int _convert; _convert; /
…… /
}

这样解决了命名冲突,但不能进行如下编码:
DoSomething(W2A(pwstr));
没有办法从代码块返回值,所以不能在函数调用中传递W2A。真笨啊,那么内联函数怎么样?

inline LPCSTR W2A(LPWSTR w) {
int_convert;
……
}

这解决了范围问题——任何W2A需要的变量多可以在这个函数中,在自己的范围内声明,不需要另外的宏。它也提供了一种返回值的方式,使你可以在函数调用和赋值中使用W2A(x)。但是这种方法不灵,也是因为W2A的缘故和其它的宏更复杂。
不管什么时候进行Unicode转换,都不能就地转换串,必须分配一个临时串容纳被转换的字节。典型地,通过调用new分配一个串:

int len = MultiByteToWideChar(..., 
mystr, NULL, 0); // 或的长度
LPWSTR p = new WCHAR[nLen]; // 分配内存
MultiByteToWideChar(...,p,len); // 转换
SomeCOMFunction(p); // 使用之
delete [] p; // 销毁


这段代码不仅令人讨厌,而且还没有效率;必须调用MultiByteToWideChar两次(一次是计算长度,一次是实际的转换),你得从堆中分配p,这样很慢。通过分配2*len个字节解决第一个问题,这里长度len是ASCII串的长度——但第二个问题怎么办?如果看看A2W是如何展开的,请看:

// 简化版
#define A2W(s) /
_len = 2*strlen(s);
AfxA2WHelper((LPWSTR)alloca(_len);


AfxA2Whelper是一个调用MultiByteToWideChar的辅助函数。A2W使用2*len巧妙地避免了两次调用MultiByteToWideChar。但A2W及其它转换宏真正聪明的地方是不调用new操作分配临时串,而是调用alloca——在栈中分配字节,而不是在堆中。这样做非常快,因为编译器要做的只是增加栈指针。不调用函数,不处理内存块。它也避免了内存碎片,并且也没有必要调用delete操作,因为当控制离开alloca被调用的地址后,内存被自动释放。这正好说明了为什么A2W不能时内联函数;如果是的话,alloca创建的临时串会在返回前被摧毁,并且你会以删除串的方式终止SomeCOMFunction(使用这个例子)调用。
A2W必须从alloca被调用的相同的地址处调用alloca——所以A2W必须是一个宏,不是一个函数;因此它需要另一个宏USERS_CONVERSION来声明_len以及其它一些用到的变量(为了简化,我省略了)。当你仔细想想,整个处理告诉我们要想写一组类似A2W的宏从栈中的分配内存会减少很多不必要的麻烦。
另外,任何时候,只要你想要快速地获取临时内存,都可以调用alloca。下面的代码是我们常常见到的:


char* p = new char[len];
DoSomething(p);
delete [] p;

使用下面的代码替代之会效率更高:

char *p = (char*)alloca(len);
DoSomething(p);
// 不用调用delete p!

当然,如果栈中的没那么多,你还这么做的话,就会出现一个讨厌的消息框。这个方法还有一些局限,详细内容请参考文档。经验告诉我,不管什么时候在MFC、ATL或其它什么地方发现奇怪的事情,最好是钻进去研究一下,你可能会发现有用的东西。







慎用USES_CONVERSION

USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。在ATL下使用要包含头文件#include "atlconv.h" 使用U...
  • nanfeiyannan
  • nanfeiyannan
  • 2012年04月18日 20:36
  • 4118

使用USES_CONVERSION

首先,先介绍下USES_CONVERSION为何物。 USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。通俗的说,就是你用了...
  • wwwgeyang777
  • wwwgeyang777
  • 2011年11月07日 16:22
  • 12348

有关USES_CONVERSION

ATL:转换宏是各种字符编码之间进行转换的一种很方便的方式,在函数调用时,它们显得非常有用。ATL转换宏的名称是根据下面的模式来命名的[源类型]2[新类型]或者[源类型]2C[新类型]。据有第二种形式...
  • P40614021
  • P40614021
  • 2011年09月15日 14:17
  • 4396

USES_CONVERSION 害得我好苦

之前用过很多次  USES_CONVERSION,然后可以方便地使用A2W、W2A来转换字符串的宽、窄,相当顺手,感觉这两个宏太好用了。如今我继续用它。 我写好了程序,写的时候已经很...
  • jszj
  • jszj
  • 2014年12月15日 20:33
  • 878

解决T2A W2A A2W的报错error C2065: “_lpw”: 未声明的标识符

当直接使用T2A W2A A2W,在编译时会出现报错:error C2065: “_lpw”: 未声明的标识符 等 解决方法: 增加头文件 #include 并在使用T2A等前加上语句 U...
  • educast
  • educast
  • 2013年09月18日 10:25
  • 9953

A2W、W2A、A2T、T2A的使用方法

1、A2W和W2A    在《Window核心编程》,多字节和宽字节之间转换比较麻烦的,MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义让我们...
  • eickandy
  • eickandy
  • 2015年07月09日 09:26
  • 10572

谨慎使用A2W等字符转换宏

在一个函数的循环体中使用A2W等字符转换宏可能引起栈溢出。 #include void fn() { while(true) { { USE...
  • educast
  • educast
  • 2013年09月22日 15:44
  • 2505

A2W、W2A、A2T、T2A的使用方法

头文件包含 #include (1)A2W的用法: [cpp] view plain copy USES_CONVERSI...
  • season1201
  • season1201
  • 2016年11月26日 00:40
  • 565

A2W、W2A、A2T、T2A的使用方法

1、A2W和W2A    在《Window核心编程》,多字节和宽字节之间转换比较麻烦的,MultiByteToWideChar函数和WideCharToMultiByte函数有足够多的参数的意义让我...
  • Qsir
  • Qsir
  • 2017年07月11日 17:53
  • 210

慎用USES_CONVERSION

USES_CONVERSION是ATL中的一个宏定义。用于编码转换(用的比较多的是CString向LPCWSTR转换)。在ATL下使用要包含头文件#include "atlconv.h" 使用USE...
  • educast
  • educast
  • 2013年12月30日 10:37
  • 1270
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:A2W、W2A、A2T、T2A、(USES_CONVERSION)
举报原因:
原因补充:

(最多只允许输入30个字)