zoukankan      html  css  js  c++  java
  • wchar_t是内置还是别名(亲测有效:wchar_t在windows下是16位整数的别名,在linux等平台下是32位整数的别名。MSVC2008开始默认是/Zc:wchar_t)

    接前一篇C++ ABI之名字改编(以Qt为例),继续看看C++名字改编相关的问题。

    问题

    • MSVC 有一对选项/Zc:wchar_t- 与 /Zc:wchar_t控制wchar_t

    • 于是 wchar_t 可以是 unsigned short 或 __wchar_t(称为原生类型?) 的别名

    两个东西混用会怎么样?

    首先考虑,会混用么?,是杞人忧天么? 由于 Qt 为 MSVC 提供的二进制包采用的前者/Zc:wchar_t-。考虑:

    • 如果你编译自己的Qt程序时,启用了后者,会怎么样?
    • 如果Qt程序同时使用了其他的C++库,而且这个库编译时采用了后者。会怎么样?

    当然

    • 我们可以自己启用 /Zc:wchar_t 来编译Qt解决这样的问题。本文不考虑这个情况。

    wchar_t

    • Unicode 4.0标准的5.2节提到:

    "The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compilershould not use wchar_t for storing Unicode text. The wchar_t type is intended for storing compiler-defined wide characters, which may be Unicode characters in some compilers."

    • C、C++ 标准对这个 wchar_t 不够明确(以至于C++0x、C1x又引入了char16_t/char32_t)
    • 各编译器实现 wchar_t 时,是通过typedef定义一个别名。在windows下是 16位整数的别名,在linux等平台下,是 32 位整数的别名。

    msvc

    MSVC,一直以来,wchar_t与其内部两个类型相关

    • unsigned short
    • __wchar_t

    wchar_t 可以是二者之一的别名,通过 /Zc:wchar_t- 与 /Zc:wchar_t进行设置

    在MSVC2008之前,默认是前者,从MSVC2008开始,默认改为了后者。

    例子

    直观一点,直接用msvc生成一个动态库,然后看看它导出的符号:

    • 源文件dll.cpp

     

    //dll.cpp
    #include <string>
    
    __declspec(dllexport) wchar_t * func1()
    {
        return 0;
    }
    
    __declspec(dllexport) void func2(wchar_t *)
    {
    }
    
    __declspec(dllexport) std::wstring generateString()
    {
        return std::wstring();
    }
    
    __declspec(dllexport) void receiveString(std::wstring str)
    {
    }
    • 分别用两种wchar_t编译上述文件,分别生成out0.dll 和 out1.dll
    cl /EHsc /Zc:wchar_t   /LD dll.cpp  /Feout0.dll
    cl /EHsc /Zc:wchar_t-  /LD dll.cpp  /Feout1.dll
    • 而后,用dumpbin查看导出的符号
    dumpbin /EXPORTS out0.dll
    dumpbin /EXPORTS out1.dll

    导出符号

    对于原生类型:注意,其中的 _W 代表 wchar_t 即 __wchar_t的类型

     ?func1@@YAPA_WXZ
     ?func2@@YAXPA_W@Z
     ?generateString@@YA?AV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@XZ
     ?receiveString@@YAXV?$basic_string@_WU?$char_traits@_W@std@@V?$allocator@_W@2@@std@@@Z

    对于unsigned short类型:注意其中的 G 代表wchar_t 即 unsigned short的类型

     ?func1@@YAPAGXZ
     ?func2@@YAXPAG@Z
     ?generateString@@YA?AV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@XZ
     ?receiveString@@YAXV?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@@Z

    两者改编后的名字不同,如果混用的话:肯定就会因为找不到要找的名字,而出现链接错误了。

    对Qt的影响

    混用两种 wchar_t 时,

    凡是使用 std::wstring 或 wchar_t 的函数都会受影响,比如

    QString QString::fromStdWString(const std::wstring & str)
    std::wstring QString::toStdWString () const
    int QString::toWCharArray(wchar_t * array) const
    QString QString::fromWCharArray(const wchar_t * string, int size = -1)

    如何解决呢?解决办法就是这种情况下不使用这些函数(似乎很不讲理哈,有些难以接受?)。

    不过http://developer.qt.nokia.com上看到有人给出一个方案,恩,尽管还是如我们刚次所说,方法是在msvc下不使用这些函数,只是似乎不是太难接受了。

    /*! 自定义的QString到std::wstring转换的封装 */
    std::wstring qToStdWString(const QString &str)
    {
    #ifdef _MSC_VER
     return std::wstring((const wchar_t *)str.utf16());
    #else
     return str.toStdWString();
    #endif
    }
     
    /*! 自定义的 std::wstring 到 QString 转换的封装 */
    QString stdWToQString(const std::wstring &str)
    {
    #ifdef _MSC_VER
     return QString::fromUtf16((const ushort *)str.c_str());
    #else
     return QString::fromStdWString(str);
    #endif
    }

    参考

    http://blog.csdn.net/dbzhang800/article/details/6707152

    ----------------------------------------------------------------------

    亲测:printf("%d",sizeof(wchar_t));

    mingw,VS2005, VS2010下wchar_t都是2个字节(使用默认设置),其中VS2010手动改成wchar_t-后,也是2个字节

    但使用QT在linux gcc下测试,wchar_t是4个字节

    ----------------------------------------------------------------------

    解决办法:

        const wchar_t *text = L"FooBar";
    
        QString s1 = QString::fromUtf16(reinterpret_cast<const ushort*>(text));
        QString s2 = QString::fromWCharArray(text);
    
        qDebug() << "sizeof(wchar_t) = " << sizeof(wchar_t);
        qDebug() << "QString::fromUtf16(reinterpret_cast<const ushort*>(text)) =>" << s1;
        qDebug() << "QString::fromWCharArray(text) =>" << s2;

    https://forum.qt.io/topic/55869/from-wchar_t-to-qstring-qstring-fromutf16-or-qstring-fromwchararray

    ----------------------------------------------------------------------

    QT编译器里也可设置:

    qmake.conf 里面设置了:
    QMAKE_CFLAGS = -nologo -Zm200 -Zc:wchar_t-

    win32 {
    QMAKE_CXXFLAGS -= -Zm200
    QMAKE_CXXFLAGS += /Zm400
    QMAKE_CXXFLAGS += /Zc:wchar_t
    }
    也可能不要设置 QMAKE_CXXFLAGS

  • 相关阅读:
    go语言练习:go实现md5
    go语言练习:结构体
    go语言练习:指针
    go语言练习:数组
    DEL: MySQL Learning
    EV: Notepad++: Insert Timestamp -- Using Python
    EV: 文件共享的问题
    EV: Ruby: 安装和运行rails
    EV: MySQL Clear Screen
    EV: Ubuntu 的root用户password问题
  • 原文地址:https://www.cnblogs.com/findumars/p/5104245.html
Copyright © 2011-2022 走看看