我有用 C-ABI 接口用 X 语言编写的 dll。
我想在我的 C++ 程序中使用这个 C-ABI。
我在main.cpp中写道:
extern "C" {
struct Foo {
const char * const data;
unsigned len;
};
struct Foo f(void);
}
int main()
{
}
并收到编译器的警告(Visual C++/15.7.5/Windows 7/32bit):
(7): 警告 C4190: 'f' 指定了 C 链接,但返回
UDT 'Foo' 与 C 不兼容
(7): 注意:参见 'Foo' 的声明
这里是神螺栓链接:https://godbolt.org/g/ztx1kf https://godbolt.org/g/ztx1kf
I read C++ 代码链接错误:警告 C4190:类型已指定 C 链接,但返回与 C 不兼容的 UDT https://stackoverflow.com/questions/22901697/error-in-c-code-linkage-warning-c4190-type-has-c-linkage-specified-but-retu,但就我而言,我没有“c++ 代码”
完全在我的 POD 结构中。
我怎样才能让编译器相信这不是C++ struct Foo
, but C struct Foo
?
我尝试将其移至单独的头文件(.h),但这没有改变任何内容。
如果我更换const char * const data
with const char *
警告消失,
我也不明白,但我不想更改结构的定义。
The x64 调用约定文档 https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019解释 UDT 返回于eax
如果它们足够小并且符合某些标准:
要在 RAX 中按值返回用户定义类型,其长度必须为 1、2、4、8、16、32 或 64 位。它还必须没有用户定义的构造函数、析构函数或复制赋值运算符;没有私有或受保护的非静态数据成员;没有引用类型的非静态数据成员;没有基类;没有虚函数;并且没有不满足这些要求的数据成员。
While Foo
is a 标准布局类型(因此我们希望它能够工作),const
非静态数据成员使复制赋值运算符被删除,这可能就是他们的意思,即使它说“用户定义”。顺便说一下,这使得它成为一个非平凡类型因此不是 C++03 意义上的 POD。
它也超出了最大尺寸,但即使我们删除了len
,以上仍然会阻止它成为“POD”。
同样,x86 调用约定文档 https://learn.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions?view=vs-2019解释类似的事情:
[...] 8 字节结构除外,这些结构在 EDX:EAX 寄存器对中返回。较大的结构在 EAX 寄存器中作为指向隐藏返回结构的指针返回。 [...]不是 POD 的结构不会在寄存器中返回。
例如,如下所示的函数:
struct Foo
{
const uint32_t x;
};
Foo f(void)
{
Foo foo = { 12345 };
return foo;
}
在x86/x64 C++模式下编译时,Foo
被视为非 POD,因此eax
/rax
包含对象的地址,正如文档引导我们期望的那样。
然而,当编译器在 x86/x64 C 模式下时,Foo
被视为 POD(我们正在编译 C),因此您将得到uint32_t
值直接在eax
.
因此,调用f
即使我们将语言链接设置为 C,来自 C 的代码也不起作用,这就是出现警告的原因。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)