
C++
最近才将x64平台上的C/
C++ ABI问题彻彻底底地梳理了一番,应该能够比较全面地回答这个问题了。首先,就像提问者所说的那样,
微软(MS)的确有一份正式的
Windows x64 ABI文档,所以我们能够认定在
Windows x64上存在一套官方的ABI。不过要注意的是,这份文档只是较为详尽地阐述了与C语言相关的ABI,像是C类型的数据表示、结构体布局、函数调用约定之类的内容。而对于
C++部分,仅仅有关于异常的描述,其他诸如之类的内容全都被省略掉了,这部分内容只能通过查看MSVC相关的实现才能知晓。不太严谨地讲,可以认为在
Windows x64上有官方的C ABI,但是并没有官方的
C++ ABI,然后我们把MSVC所采用的
C++ ABI称作MSVC
C++ ABI。现在我们来探讨一下MinGW64,MinGW64可以被视为GNU工具链的
Windows移植版本,它也有一份MinGW x64软件约定。但很遗憾的是,这里也主要是对C语言部分进行了描述。从其描述来看,MinGW64所使用的C ABI基本上就是
Windows x64 ABI。只有极少数的细节方面存在差异,例如在MinGW64 GCC中,long double的默认大小是16字节,而在MSVC中则是8字节。只要不涉及到这些极少数的不同之处,使用MinGW GCC和MSVC编译出来的C语言二进制产物是完全能够混合使用的。MinGW GCC所使用的
C++ ABI仍然是在
linux上使用的Itanium
C++ ABI,而Itanium
C++ ABI与MSVC
C++ ABI是不兼容的。首先,它们的名字改编(name mangling)规则就不一样,在进行链接的时候就会报未定义符号(undefined symbol)的错误。这个时候你肯定会想,我只要用extern C来修饰
C++函数,不就能够解决链接错误了吗?确实是这样的,如果用extern C来修饰函数的话,那么它们都会按照C语言的规则进行名字改编,符号就会一致了。链接错误虽然解决了,但是在运行的时候可能会出错。到底会不会出错?这就涉及到数据表示和调用约定了。假设将下面的代码用MSVC编译成一个库(静态库或者动态库都一样),然后在GCC这边调用这个函数。