LPCTSTR和LPCSTR转换
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LPCTSTR和LPCSTR转换相关的知识,希望对你有一定的参考价值。
在VC9下,怎么把TCHAR*转换成LPCSTR,怎么把CString转换成LPCSTR。要例子
参考技术A 例子没有。。。思路写下:
如果你工程设置是unicode,那么TCHAR会解析成wchar,所以你需要使用宽字符转多字节的函数转成LPCSTR,如果你工程设置的是多字节集,那么直接强制转换成LPCSTR就行。。。
CString::GetBuffer()得到的就是TCHAR* 参考技术B LPCTSTR 在Unicode下是const WCHAR*
LPCSTR 其实就是const char*
转换方法为
LPCSTR a=“123”;
wchar_t ws[100];
swprintf(ws, 100, L"%hs", a);
LPCTSTR b;
b=(LPCTSTR)ws;
ANSI与Unicode编码,TCHAR | LPSTR | LPCSTR | LPWSTR | LPCWSTR | LPTSTR | LPCTSTR 的含义
一个字符可以用1-byte表示,即ANSI编码;
一个字符也可用2-bytes表示,即Unicode编码(Unicode其实还包含了更多内容,不止2-bytes)。
Visual C++支持char和wchar_t作为ANSI和Unicode的原始数据类型。
例如
char cResponse; // \'Y\' or \'N\' char sUsername[64]; // str* functions
以及
wchar_t cResponse; // \'Y\' or \'N\' wchar_t sUsername[64]; // wcs* functions
它们可以统一写成
#include<TCHAR.H> // Implicit or explicit include TCHAR cResponse; // \'Y\' or \'N\' TCHAR sUsername[64]; // _tcs* functions
TCHAR则是根据选择的字符集决定是翻译成char还是wchar_t,字符集的设置如下:
所以TCHAR的定义如下:
#ifdef _UNICODE typedef wchar_t TCHAR; #else typedef char TCHAR; #endif
在windows中,一般前缀 T 代表了它可以自适应不同的字符集。
比如:strcpy,strlen,strcat(包括安全后缀_s)代表ANSI版本;
wcscpy,wcslen,wcscat(包括安全后缀_s),代表Unicode版本,这里WC代表Wide Character;
_tcscpy,_tcslen,_tcscat则视情况而定:
size_t strlen(const char*); //ANSI size_t wcslen(const wchar_t* ); //Unicdoe size_t _tcslen(const TCHAR* ); //ANSI or Unicode
我们知道一个string使用双引号表示,这种表示说明它是一个ANSI-string,每个字符占1-byte,例如:
"This is ANSI String. Each letter takes 1 byte."
要转换成Unicdeo-string需要加前缀:L
[__strong__]L"This is Unicode string. Each letter would take 2 bytes, including spaces."
Unicode编码的字符,每个都占用2-bytes,哪怕是可以用1-byte表示的,比如英文字母,数字,null字符等。所以一个unicode-string占用的字节总是2-bytes的倍数。
结合上面提到的 T 前缀,一种适用于两种字符集的写法是这样的:
"ANSI String"; // ANSI L"Unicode String"; // Unicode _T("Either string, depending on compilation"); // ANSI or Unicode
_T或TEXT是一个宏定义,它与前缀 T 表示的意思一样,定义如下:
// SIMPLIFIED #ifdef _UNICODE #define _T(c) L##c #define TEXT(c) L##c #else #define _T(c) c #define TEXT(c) c #endif
上面的##叫“token-pasting operator”。在Unicode下,_T("Unicode")被翻译成 L"Unicode";在ANSI下,_T("Unicode")被翻译成 “Unicode”。
注意,不能通过_T来转换一个变量(string or character),下面的操作是不允许的:
char c = \'C\'; char str[16] = "CodeProject"; _T(c); _T(str);
如果你是在ANSI(Multi-Byte)下编译,可以顺利通过,_T(c), _T(str)被翻译成c, str;
但是在Unicode下编译,就会报错:
error C2065: \'Lc\' : undeclared identifier error C2065: \'Lstr\' : undeclared identifier
结合_T的定义不难弄懂。
在windows中,几乎所有需要传入string或character的API,都有通用的版本,例如: SetWindowTextA/W,就可以统一写成:
BOOL SetWindowText(HWND, const TCHAR*);
但我们知道SetWindowText是一个宏,它代表了以下两种之一:
BOOL SetWindowTextA(HWND, const char*); BOOL SetWindowTextW(HWND, const wchar_t*);
但其实,在内部实现时,不论ANSI还是Unicode都统一通过Unicode方式实现,当你调用 SetWindowTextA 时(传入ANSI-string),它会先转化成Unicode-string,再调用 SetWindowTextW实现。真正发挥作用的只有Unicode的版本!
所以在写代码时建议是直接调用Unicode版本的api,尽管我们对ANSI版本的string更熟悉。
Note:存在另外一个typedef:WCHAR,它等价于wchar_t。
我们知道strlen定义如下:
size_t strlen(const char*);
它也可以写成
size_t strlen(LPCSTR);
所以
// Simplified typedef const char* LPCSTR;
它的含义如下
- LP: Long Pointer
- C: Constant
- STR: String
Long Pointer与Pointer意思一样。
举一反三,对于Unicode字符,我们有:
size_t wcslen(const wchar_t* szString); // Or WCHAR* size_t wcslen(LPCWSTR szString);
这里 LPCWSTR代表
typedef const WCHAR* LPCWSTR;
它的含义如下
- LP - Pointer
- C - Constant
- WSTR - Wide character String
更进一步,有LPCTSTR
- LP - Pointer
- C - Constant
- T = TCHAR
- STR = String
总结:
- TCHAR - char / wchar_t (取决于字符集)
- LPSTR - char*
- LPCSTR - const char*
- LPWSTR - wchar_t*
- LPCWSTR - const wchar_t*
- LPTSTR - TCHAR*
- LPCTSTR - const TCHAR*
在编程中有时候会因为选择的字符集不同,而编译出错,如下面的写法在ANSI下没事,但在Unicode下就会报错:
int main() { TCHAR name[] = "Saturn"; int nLen; // Or size_t lLen = strlen(name); }
- error C2440: \'initializing\' : cannot convert from \'const char [7]\' to \'TCHAR []\'
- error C2664: \'strlen\' : cannot convert parameter 1 from \'TCHAR []\' to \'const char *\'
同样的问题出现在:
nLen = wcslen("Saturn"); // ERROR: cannot convert parameter 1 from \'const char [7]\' to \'const wchar_t *\'
遗憾的是,上面的错误不能通过强制转换的方法修改:
nLen = wcslen((const wchar_t*)"Saturn");
上面的写法会得到错误的结果,往往导致越界。原因是“Saturn”占用7个字节
\'S\'(83) | \'a\'(97) | \'t\'(116) | \'u\'(117) | \'r\'(114) | \'n\'(110) | \'\\0\'(0) |
但传给wcslen的时候,对于每个字符分配2-bytes。因此头两个字节[83,97]被看作一个字符,value:(97<<8 | 83),是字符\'?\'.后面的以此类推。
所以如果用Unicode的api,需要提前转换:
TCHAR name[] = _T("Saturn"); //或者 wcslen(L"Saturn");
在之前的例子中,strlen(name)中的name在Unicode下编译,每个字符占2-bytes,如果强制转换成ANSI:
lLen = strlen ((const char*)name);
也会出现问题,‘S\'原来表示为[83,0],但在ANSI中第一个字节[83]可以被正确翻译成\'S\',但接着第二个字节[0]直接被翻译为为\'\\0\',结束了整个字符串。所以strlen得到的结果为1。
综上,C语言风格的强制转换在这里是行不通的。
如果需要分配内存,在C++中通过new直接指定字符的个数,不用去管具体分配了多少字节:
LPTSTR pBuffer; // TCHAR* pBuffer = new TCHAR[128]; // Allocates 128 or 256 BYTES, depending on compilation.
但如果你是用malloc,LocalAlloc,GlobalAlloc这类api分配空间,就需要指定具体的字节数:
pBuffer = (TCHAR*) malloc (128 * sizeof(TCHAR) );
以上是关于LPCTSTR和LPCSTR转换的主要内容,如果未能解决你的问题,请参考以下文章
ANSI与Unicode编码,TCHAR | LPSTR | LPCSTR | LPWSTR | LPCWSTR | LPTSTR | LPCTSTR 的含义