none
C++编译器对函数名字改编的bug RRS feed

  • 问题

  • 在C++ Window开发(控制台开发不会有这个问题),如果自定义的类有成员函数名字为SetWindowText或者GetWindowText,编译器编在编译时会根据当前设置的字符集把这两个成员函数改名。如果字符集为多字节,SetWindowText则变为SetWindowTextA,如果为UNICODE,则变为SetWindowTextW。GetWindowText函数名字也一样的规则。如void GDI::Window::SetWindowText(const char* pszText)函数,在多字节字符集则为

    ?SetWindowTextA@Window@GDI@@QEAAXPEBD@Z ()

    很明显,编译器根据系统中的SetWindowText和GetWindowText 两个API的声明环境来进行改编了,系统中这两个API是一个宏定义,根据不同字符集分别指向SetWindowTextA/SetWindowTextW和GetWindowTextA/GetWindowTextW。

    对于一般程序正常使用,这样的名字改编没有问题,但是如果包含SetWindowText/GetWindowText函数的自定义类在DLL中,导出这些函数时就会出现问题。如DLL是多字节字符集编译的,那么使用这些函数的应用也必须为多字节字符集,否则就会出现问题。编译器把你调用SetWindowText的代码中的SetWindowText改编为  ?SetWindowTextW@,因为DLL不存在这个名字,所以链接不通过。如果使用SetWindowTextA这样调用,则编译时就会报错,找不到该函数的定义。

    从visual studio 2010到visual studio 2015都存在这个问题,之前的版本没有测试过,不清楚是否有这个bug。

    请问一下编译器有何设置可以避免这个bug

    2016年1月17日 6:28

答案

  • 这个不是bug,是C++的预处理宏的特性。不想要这个预处理的话,把受影响的代码搬到一个不包含windows.h的cpp文件就可以。

    另外,你应该要求DLL作者提供Unicode版本的库文件和二进制文件(例如mfc120u.lib和MFC120U.dll)以避免可能的头文件编译出来的接口和DLL文件提供的不一致的问题(比如DLL接口包含CString这样的)。



    Visual C++ MVP

    2016年1月18日 1:31
    版主

全部回复

  • 您好,

    》对于一般程序正常使用,这样的名字改编没有问题,但是如果包含SetWindowText/GetWindowText函数的自定义类在DLL中,导出这些函数时就会出现问题。如DLL是多字节字符集编译的,那么使用这些函数的应用也必须为多字节字符集,否则就会出现问题。编译器把你调用SetWindowText的代码中的SetWindowText改编为  ?SetWindowTextW@,因为DLL不存在这个名字,所以链接不通过。如果使用SetWindowTextA这样调用,则编译时就会报错,找不到该函数的定义。

    一般为了程序的兼容性考虑,我们建议统一程序的字符集设置,要么都为多字节字符集编译,要么都用Unicode。如果dll是多字节的,应用程序是Unicode,在调用时要特别注意,需要将参数进行类型转换后再传入符合标准的参数。

    您可以用WideCharToMultiByte将Unicode参数转为MultiByte参数,然后调用dll函数;继而用MultiByteToWideChar将返回值或输出参数转为Unicode。

    May
     
     


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2016年1月17日 9:22
  • 这个不是bug,是C++的预处理宏的特性。不想要这个预处理的话,把受影响的代码搬到一个不包含windows.h的cpp文件就可以。

    另外,你应该要求DLL作者提供Unicode版本的库文件和二进制文件(例如mfc120u.lib和MFC120U.dll)以避免可能的头文件编译出来的接口和DLL文件提供的不一致的问题(比如DLL接口包含CString这样的)。



    Visual C++ MVP

    2016年1月18日 1:31
    版主
  • WideCharToMultiByte将Unicode参数转为MultiByte参数

    这个方法解决不了问题,因为dll是和应用字符集不一致的情况最后是链接不通过,而不是参数传递导致的问题

    2016年1月19日 3:29
  • 这个不是bug,是C++的预处理宏的特性。不想要这个预处理的话,把受影响的代码搬到一个不包含windows.h的cpp文件就可以。

    另外,你应该要求DLL作者提供Unicode版本的库文件和二进制文件(例如mfc120u.lib和MFC120U.dll)以避免可能的头文件编译出来的接口和DLL文件提供的不一致的问题(比如DLL接口包含CString这样的)。



    Visual C++ MVP

    C++的预处理宏为啥只处理SetWindowText/GetWindowText这两个函数名?(我估计凡是涉及到字符串系统API都可能),但是其他的名字就不会有这个问题
    2016年1月19日 3:33
  • windows.h里面这种宏一大堆,不是只有这两个函数,和C++本身也没有关系,包含来自不同作者的头文件时出现重名是很常见的问题。


    Visual C++ MVP

    2016年1月27日 13:21
    版主