c++ - 如何定义 C 结构:c-linkage 和 udt
问题描述
我用 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 链接,但返回与 C 不兼容的 UDT 'Foo'
(7): 注意:见 'Foo' 的声明
这里godbolt链接:https ://godbolt.org/g/ztx1kf
我阅读了 C++ 代码链接中的错误:警告 C4190:类型已指定 C 链接,但返回与 C 不兼容的 UDT,但在我的情况下,我的 POD 结构中根本没有“c++ 代码”。
我怎样才能说服编译器这不是C++ struct Foo
,而是C struct Foo
?
我尝试将其移动到单独的头文件(.h),但这没有任何改变。
如果我const char * const data
用const char *
警告消失代替,我也不明白,但我不想改变结构的定义。
解决方案
x64 调用约定文档解释说,eax
如果 UDT 足够小并且符合某些标准,则会返回它们:
要在 RAX 中按值返回用户定义的类型,它的长度必须为 1、2、4、8、16、32 或 64 位。它还必须没有用户定义的构造函数、析构函数或复制赋值运算符;没有私有或受保护的非静态数据成员;没有引用类型的非静态数据成员;没有基类;没有虚函数;并且没有不符合这些要求的数据成员。
虽然Foo
是一个StandardLayout类型(因此我们希望它可以工作),但const
非静态数据成员使复制赋值运算符被删除,这可能就是他们的意思,即使它说“用户定义”。顺便说一句,这使它成为非TrivialType,因此不是 C++03 意义上的 POD。
它也超过了最大大小,但即使我们删除len
了 ,上面仍然会阻止它成为“POD”。
同样,x86 调用约定文档解释了类似的内容:
[...] 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调用也不起作用,这就是出现警告的原因。
推荐阅读
- selenium - 无法使用编码的 ui 在 chrome 浏览器中启动应用程序
- amazon-web-services - 管理数百万台设备对 AWS S3 的访问
- cassandra - 包含 IN 的 Cassandra 语句,在具有集合列类型的表上
- docker - 如何限制 docker 容器内的 ArangoDB RAM 使用?
- react-native - React Native Code 未运行,出现错误 - 连接到 localhost 端口 8081 [tcp/sunproxyadmin] 成功
- c# - ASP.NET:我正在尝试设置一个标签来显示一个图像按钮,但它没有显示任何页面,我该怎么做?
- javascript - 使用什么工具集来创建这些很酷的动画和有趣的页面设计?
- sql - 选择部分匹配的查询
- razor - 如何在 sitefinity 画廊中的图像中添加潜台词?
- sql - 备份 db2 中的特定表