sor*_*bet 7 arrays memory-management d shared-memory slice
接受C风格数组作为参数的最佳方法是什么,将其修改为D风格的数组(包括更改长度),并将其作为C风格的数组返回?
我在D中编写一个库,它编译成带有C接口的DLL(我将从C++调用我的D DLL,因此需要C接口).
它需要byte数组并修改它们的内容,有时会改变数组长度.
因为我使用的是C接口,所以我的函数必须接受C风格的数组.理想情况下,bufferMaxSize如果给定的缓冲区太小,我希望能够分配更多的内存(即扩展).
这就是我的D DLL现在接受参数的方式:
// D library code; compiles to DLL with C interface.
// bufferSize is the data length, and is a pointer because I may modify the data length.
// bufferMaxSize is the total allocated buffer size.
export extern(C) void patchData(const size_t bufferMaxSize, size_t * bufferSize, byte * buffer) { ... }
Run Code Online (Sandbox Code Playgroud)
在我的D库中,我有现有的代码,可以接受D风格的数组.沿着这条线的某个地方,必须将C风格的数组转换为D风格的数组.
我正在进行这样的转换(简化示例):
// D library code; compiles to DLL with C interface.
export extern(C) void patchData(const size_t bufferMaxSize, size_t * bufferSize, byte * buffer) {
// Convert from C-style array to D-style.
byte[] dStyleArray = buffer[0 .. *bufferSize];
// Modify data.
dStyleArray[0] = cast(byte) 0xab;
dStyleArray[1] = cast(byte) 0xbc;
dStyleArray.length = dStyleArray.length + 16;
// Return modified data as C-style array.
buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];
*bufferSize = dStyleArray.length;
}
Run Code Online (Sandbox Code Playgroud)
它有效,但我不确定这里到底发生了什么.我主要担心的是速度.如果我循环遍历此函数,我不希望不断地分配新内存并来回复制其内容.
当我这样做时byte[] dStyleArray = buffer[0 .. *bufferSize],D是否分配了一大块内存并将所有内容复制到D风格的数组中,还是指向已经分配的C风格数组?
我什么时候发生了什么事dStyleArray.length = dStyleArray.length + 16?从dStyleArray切片开始buffer,我现在分配新的内存/复制内存吗?还是我延伸到buffer?
当我这样做时buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];,我正在复制记忆,对吧?
是否可以将D风格的数组"绑定"到C风格的数组,并通过D风格的数组接口访问预先分配的内存?
小智 5
当我执行byte [] dStyleArray = buffer [0 ..*bufferSize]时,D是否分配了一大块内存并将所有内容复制到D-style数组中,还是指向已经分配的C风格数组?
它指向.Phobos使用相同的技巧将C"字符串"转换为D字符串:https: //github.com/D-Programming-Language/phobos/blob/67c95e6de21d5d627e3c57128b4d6e332c82f785/std/string.d#L208-L211
当我做dStyleArray.length = dStyleArray.length + 16时会发生什么?由于dStyleArray是从缓冲区切片的,我现在要分配新的内存/复制内存吗?或者我延伸到缓冲区?
这可能不是你想要/期望的.它将在垃圾收集的内存上分配一个新块,并将内容复制到它.它无法扩展它,因为运行时没有关于内存块的任何信息(它没有管理它).你真的想扩展缓冲区,或移动指针(在D中切片)?
当我做缓冲[0 .. dStyleArray.length] = dStyleArray [0 .. dStyleArray.length];时,我正在复制内存,对吗?
是.那降到了memcpy.
是否可以将D风格的数组"绑定"到C风格的数组,并通过D风格的数组接口访问预先分配的内存?
是的,这就是你在开始时所做的;)
如果您只想更改数组的前2个元素,只需进行绑定并更改它们,它就会"正常工作".
如果你想测试行为,我建议你unittest在函数下面放一个块,这样你就可以通过给它指针来测试会发生什么.另外,如果你想确保你没有进行任何GC分配,你可能需要考虑@nogc使用你的函数来静态检查它(nothrow对于C函数来说通常也是一个好主意).
当我执行 byte[] dStyleArray = buffer[0 .. *bufferSize] 时,D 是否分配新的内存块并将所有内容复制到 D 样式数组中,还是指向已分配的 C 样式数组?
它只是指向它。右侧的切片运算符(概念上)相同array.pointer = &first_element; array._length = length;- 一个非常快速且简单的操作。(我_length之所以这样称呼它,而不是顺便length说一句,是因为设置 length 属性实际上可能会调用一个函数,这是下一个。)
当我执行 dStyleArray.length = dStyleArray.length + 16 时会发生什么?
这将分配新的内存。当长度扩展时,除非运行时可以证明它是安全的(或者你告诉它假设它是安全的并且它知道它来自 GC),否则数组将被复制到新位置。它基本上调用realloc()指针 - 虽然不是字面上的意思,但它与 C realloc 不兼容。
由于它来自 C,运行时只知道它不拥有内存,而是以某种方式在其他地方进行管理,并且在尝试扩展时总是会分配一个新内存。如果您想通过其他方式进行扩展,则需要自己进行。
当我执行 buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length]; 时,我正在复制内存,对吗?
对,这确实复制了,因为你在左边切了。
是否可以将 D 样式数组“绑定”到 C 样式数组,并通过 D 样式数组的接口访问预分配的内存?
普通的右手切片:
auto d_array = c_array[0 .. c_array_length];
除了长度扩展之外,它可以处理所有事情。它保留指针,因此写入元素将立即影响原始内容。(顺便说一句,因为它是共享的 C 内存,所以请确保在 D 仍在使用它时不要这样做free!只要您只在这个函数中使用它,而不将切片存储在任何地方,就应该没问题。)
如果确实需要延长长度,则需要自己进行。我喜欢的方法是将整个潜在数组(完整容量)切片,然后再次切片以获得有限的容量窗口。
所以就像也许:
auto whole_array = buffer[0 .. bufferMaxSize]; // assuming buffer is already fully allocated on the C side
auto part_youre_using = whole_array[0 .. *bufferSize];
// to extend:
*bufferSize += 16; // extend the size
part_your_using = whole_array[0 .. *bufferSize]; // and reslice from the original
Run Code Online (Sandbox Code Playgroud)
我制作 Whole_array 而不是重新切片的原因buffer是 D 可以为我捕获边界违规。它不会在裸指针上执行此操作,但会在切片指针上执行此操作,因为它知道最大大小为其长度。
如果您需要扩展缓冲区,请使用正确的 C 函数(例如realloc或其他函数)来完成,然后再次切出 Whole_array 和 Part_youre_using 。