• TCHAR,WCHAR,LPSTR,LPWSTR,LPCTSR的区别


                在C++的窗口应用程序开发过程中,我们经常对TCHAR,LPCTSTR这样的关键字迷惑。接下来将详细解释他们之间的区别。
              通常,一个字符可以用1个字节或两个字节来表示。1个字节的字符为ANSI编码字符,通常所有的英文字符都采用ANSI编码。2个字节的字符为Unicode编码,可以表示世界上所有的语言。

              在VC++编译器中,分别用charwchar_t数据类型来标志ANSIUnicode编码的字符。为了理解方便,我们可以认为两字节字符是Windows操作系统用例支持多语言的方法。Microsoft WindowsUTF-16字符编码来代表2字节编码。怎么样能让你的C/C++代码不依赖于具体的字符编码呢?

    建议1:用一般的数据类型和名字代表字符和字符串

     例如:char cResponse; // 'Y' or 'N'

    char sUsername[64];

    用下面的方式来替代:

    wchar_t cResponse; // 'Y' or 'N'

    wchar_t sUsername[64];

    为了支持多语言(Unicode),可以用下面的方式:

    #include<TCHAR.H> // Implicit or explicit include

    TCHAR cResponse; // 'Y' or 'N'

    TCHAR sUsername[64];//字符串

    在项目设置中,选择配置选项卡的常规,然后选择字符集。选择使用Unicode字符集。

    设置好了以后,当你的项目用该字符集编译时,TCHAR会被翻译成wchar_t.当用ANSI/MBCS编译,则翻译成char。你可以通过项目设置很方便的使用charwchar_t,不会受到关键字的影响。

     

    TCHAR的定义如下:

    #ifdef _UNICODE

    typedef wchar_t TCHAR;

    #else

    typedef char TCHAR;

    #endif

    当你设置字符集为“使用Unicode字符集”时,宏_UNICODE就已经定义,这时候TCHAR代表wchar_t,当字符集设置为“使用多字节字符集”时,TCHAR代表char

    与此类似,为了让单个函数支持多种字符集或多种语言,应该使用特殊的函数()

    可以使用_tcscpy,_tcslen,_tcscat函数代替strcpy, strlen, strcat(包括后缀为_s的函数)wcscpy, wcslen, wcscat

     

       strlen的原型如下:

    size_t strlen(const char*);

    wcslen的原型如下:

    size_t wcslen(const wchar_t* );

    使用_tcslen的原型如下:

    size_t _tcslen(const TCHAR* );

     

    WC是为宽字符而设计的,因此wcs表示宽字符串。_tcs表示_T字符集串。_T可能代表char或者wchar_T。但是实际上,_tcslen(或其他的_tcs开头的函数)并不是函数,它们是宏。他们的定义如下:

    #ifdef _UNICODE

    #define _tcslen wcslen

    #else

    #define _tcslen strlen

    #endif

    该宏定义在头文件TCHAR.h中。

    大家可能会问为什么它们定义成宏而不是函数?原因很简单,一个库或DLL可能导出与之相同的函数原型,忽略C++的重载。如下,你可能会导出如下函数:

    void _TPrintChar(char);

    客户端怎么按意图调用它呢?

    void _TPrintChar(wchar_t);

    _TPrintChar函数不能将该函数的参数变成2字节字符集,可能使用两个函数:

    void PrintCharA(char); // A = ANSI

    void PrintCharW(wchar_t);//W=wide character

    可以简单地使用宏来定义,如下:

    #ifdef _UNICODE

    void _TPrintChar(wchar_t);

    #else

    void _TPrintChar(char);

    #endif

    客户端可以简单的调用:

    TCHAR cChar;

    _TPrintChar(cChar);

    宏可以帮助我们很方便的使用ANSI或Unicode函数,为了方便,可以使用宏来定义SetWindowText函数:

    // WinUser.H

    #ifdef UNICODE

    #define SetWindowText  SetWindowTextW

    #else

    #define SetWindowText  SetWindowTextA

    #endif //!UNICODE

     

    ANSI字符集:"This is ANSI String. Each letter takes 1 byte."每个字符占一个字节,不是Unicode编码,为了代表Unicode字符串,可以用前缀L,如下:

    L"This is Unicode string. Each letter would take 2 bytes, including spaces."

    在字符串前面的L表示把该字符串转换为Unicode字符串。转换后的字符串的源字符串长度的两倍。

    你可以使用下面的方式来判断使用具体的字符集:

    "ANSI String"; // ANSI

    L"Unicode String"; // Unicode

     

    _T("Either string, depending on compilation"); // ANSI or Unicode

    // or use TEXT macro, if you need more readability

    对于ANSI字符串没有前缀,对于Unicode字符集采用L前缀,使用前缀_T或TEXT可以根据编译器的设置来确定字符集,_T和TEXT都是宏,定义如下:

    // SIMPLIFIED

    #ifdef _UNICODE

     #define _T(c) L##c

     #define TEXT(c) L##c

    #else

     #define _T(c) c

     #define TEXT(c) c

    #endif

    符号##是标记运算符,当字符串通过该宏传递参数进去可以将_T("Unicode") into L"Unicode",该标记符在C/C++中都存在。

    但是不能使用该宏将一个变量(字符和字符串)转变成Unicode文本或non-Unicode文本。如下:

    char c = 'C';

    char str[16] = "CodeProject";

    _T(c);

    _T(str);

    上面的代码将出现编译错误。_T(c)_T(str)ANSI编译模式下可以通过编译。

    Windows API中存在大量的以字符串和字符为参数的函数,如SetWindowTextA/W

    BOOL SetWindowText(HWND, const TCHAR*);

    SetWindowText是一个宏,根据编译环境的设置来决定。

    BOOL SetWindowTextA(HWND, const char*);

    BOOL SetWindowTextW(HWND, const wchar_t*);

    使用下面的方法获取该函数的地址是错误的:

    HMODULE hDLLHandle;

    FARPROC pFuncPtr;

     

    hDLLHandle = LoadLibrary(L"user32.dll");

     

    pFuncPtr = GetProcAddress(hDLLHandle, "SetWindowText");

    //pFuncPtr 为空, 因为不存在名字为SetWindowText的函数。

    对于User32.DLL导出的函数是SetWindowTextASetWindowTextW不是函数SetWindowText.

     

     

     

    .NET框架中,可以很方便的标志导出的函数:

    [DllImport("user32.dll")]

    extern public static int SetWindowText(IntPtr hWnd, string lpString);

     

    同时存在另一个宏:WCHAR等同于wchar_t.

     

    TCHAR是单个字符,我们可以定义TCHAR数组或字符指针:

    // ANSI characters

    foo_ansi(char*);

    foo_ansi(const char*);

    /*const*/ char* pString;

     

    // Unicode/wide-string

    foo_uni(WCHAR*);

    wchar_t* foo_uni(const WCHAR*);

    /*const*/ WCHAR* pString;

     

    // Independent

    foo_char(TCHAR*);

    foo_char(const TCHAR*);

    /*const*/ TCHAR* pString;

    从上面可以看出,使用TCHAR是最好的选择。

    我们知道strlen的两个版本:

    size_t strlen(const char*);

    size_t strlen(LPCSTR);

    但是LPCSTR是通过typedef定义的。typedef const char* LPCSTR; 

    LP:代表长指针    C:代表常量   STR:代表字符串

    LPCSTR would mean (Long) Pointer to a Constant String.

     

     

    对于strcpy:

    LPSTR strcpy(LPSTR szTarget, LPCSTR szSource);

    szTargetLPSTR类型,定义如下:

    typedef char* LPSTR;

    上面的函数都是针对ANSI字符串集,如果要支持Unicode字符集,要计算宽字符的长度使用wcslen

    size_t nLength;

    nLength = wcslen(L"Unicode");

     

    wcslen的定义如下:

    size_t wcslen(const wchar_t* szString); // Or WCHAR*

    或者:size_t wcslen(LPCWSTR szString);

     

    LPCWSTR的定义如下:

    typedef const WCHAR* LPCWSTR;

    LP:代表指针;C代表常数;WSTR:宽字符串

     

    strlen, wcslen or _tcslen返回的是字符串字符的个数不是字节数。

     

    一个具体的例子:

    int main()

    {

        TCHAR name[] = "Saturn";

        int nLen; // Or size_t

     

    lLen = strlen(name);

    }

    上面的代码以ANSI字符集可以正常编译,此时TCHARchar.当在Unicode字符集下编译会出现错误,应该改成:TCHAR name[] = _T("Saturn");

  • 相关阅读:
    ArcEngine 图层标注 (根据字段、角度)
    以Graphicslayer为管理组来管理Element.
    ServletContextAware、ServletRequestAware、ServletResponseAware、SessionAware
    web.xml配置错误页面,及输出错误信息
    ServletContextListener使用详解
    自定义异常类。
    Hibernate注解与JPA
    Spring事务管理-<tx:advice>标签
    Spring配置之OpenSessionInViewFilter
    巧用Ajax的beforeSend 提高用户体验
  • 原文地址:https://www.cnblogs.com/xinyuyuanm/p/2990623.html
Copyright © 2020-2023  润新知