我正在实现一个 C 代码,该代码必须返回超过 4000 个自定义结构条目给 flutter 应用程序。该代码在 1000 个条目下运行良好,但当它返回 4000 左右时,flutter 应用程序崩溃并出现以下错误:
这是C结构体代码:
struct Win32ReadFileResult {
int result = 0;
int length = 0;
list<Win32ReadFile> files = {};
};
这是该结构的 flutter 类:
base class Win32ReadFileResult extends Struct {
@Uint32()
external int result;
@Uint32()
external int length;
@Array(1000)
external Array<Win32ReadFile> files;
}
如果我将
@Array(1000)
注释更改为 @Array(4000)
,应用程序在调用 C 程序时会崩溃。
我不知道这是否是返回在 C dll 中创建的对象列表的最佳方法,或者也许我在 flutter 中的结构定义中有一些错误。
您没有提供有关您的问题的太多背景信息,但以下是一些可观察到的问题:
1.这个
Win32ReadFileResult
结构绝对不是 C。基于 list<Win32ReadFile>
,我假设您使用了 C++ 中的 std:list
容器,并全局导入了 std
命名空间。不要通过结构体跨越语言边界传递 C++ 类,特别是如果它们需要 C! dart 应该如何知道类的内存布局?
2.我怀疑
std:list
和 @Array
对于您的用例是否正确。 cppreference 说:
std::list 是一个容器,支持从容器中的任何位置恒定时间插入和删除元素。不支持快速随机访问。它通常被实现为双向链表。
因此,您使用的容器甚至不需要像数组那样将元素存储在连续的内存块中。另一方面,dart ffi 文档 说:
数组 - 固定大小的项目数组。
据我所知,您的
std:list
是动态调整大小的,所以如果您指定列表中只有 2000 个元素的 @Array(4000)
会发生什么? @Array
适用于 char[10]
等结构体字段,但不适用于列表。
C端修复方法:
将指针传递给元素
files
和元素计数 length
。将元素存储在连续的内存块中,可以使用 new
进行分配。使用delete
提供再次释放内存的功能。例如:
struct Win32ReadFileList {
int result = 0;
int length = 0;
Win32ReadFile* files = nullptr;
};
Win32ReadFileList GetReadFileList(...) {
Win32ReadFileList fileList;
fileList.files = new Win32ReadFile[...]();
return fileList;
}
void FreeReadFileList(Win32ReadFileList fileList) {
delete[] fileList.files;
}
如何修复 Dart 端:
使用
Pointer<Win32ReadFile>
代替 Array<Win32ReadFile>
并使用元素指针和元素计数访问 Win32ReadFile
元素。我目前不知道这在 dart 中是如何完成的,因为我从未使用过 dart ffi。