如何将 C 样式数组修改为 D 样式数组?
How can I modify a C-style array as D-style array?
问题
接受C风格数组作为参数,将其修改为D风格数组(包括更改长度),并return将其作为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) { ... }
在我的 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;
}
它有效,但我不确定这里到底发生了什么。我主要关心的是速度。如果我循环执行此函数,我不想不断分配新内存并来回复制其内容。
当我执行 byte[] dStyleArray = buffer[0 .. *bufferSize]
时,D 是在分配新的内存块并将所有内容复制到 D 样式数组中,还是指向已分配的 C 样式数组?
当我执行 dStyleArray.length = dStyleArray.length + 16
时发生了什么?由于 dStyleArray
是从 buffer
切分出来的,我现在要分配新的 memory/copying 内存吗?或者我扩展到 buffer
?
当我buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];
时,我是复制内存,对吗?
是否可以只"bind"将 D 样式数组转换为 C 样式数组,并通过 D 样式数组的接口访问预分配的内存?
When I do byte[] dStyleArray = buffer[0 .. *bufferSize], is D allocating a new chunk of memory and copying everything into the D-style array, or is it pointing to the already-allocated C-style array?
它只是指向它。右侧的切片运算符(概念上)与 array.pointer = &first_element; array._length = length;
相同 - 非常快速和简单的操作。 (我称它为 _length
而不是 length
顺便说一句,因为设置长度 属性 实际上可能会调用一个函数,这是下一个。)
What's going on when I do dStyleArray.length = dStyleArray.length + 16?
那将分配新的内存。当长度被扩展时,除非运行时可以证明它是安全的(或者你告诉它假设它是安全的并且它知道它来自 GC),否则该数组将被复制到一个新位置。它基本上在指针上调用 realloc()
- 虽然不是字面意思,但它与 C realloc 不兼容。
由于它来自 C,运行时只知道它不拥有内存,它以某种方式在别处管理,并且在尝试扩展时总是会分配一个新内存。如果你想通过其他方式扩展,你需要自己做。
When I do buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];, I am copying memory, right?
对,确实复制了,因为您在左侧切片。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
普通的右手切片:
auto d_array = c_array[0 .. c_array_length];
处理除长度扩展之外的所有内容。它保留指针,因此写入元素会立即影响原始内容。 (顺便说一句,因为它是共享的 C 内存,请确保在 D 仍在使用它时不要 free
它!只要你只在这个函数中使用它就可以了,但不要将切片存储在任何地方.)
如果确实需要加长,需要自己动手。我喜欢这样做的方式是对整个潜在数组进行切片,满容量,然后再次切片以获得有限的容量 window.
所以可能:
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
我做 whole_array 而不是重新切片 buffer
的原因是 D 可以为我捕获越界行为。它不会在裸指针上执行此操作,但会在切片指针上执行此操作,因为它知道最大大小作为其长度。
如果您需要扩展缓冲区,请使用正确的 C 函数来执行此操作,例如 realloc
或其他任何内容,然后再次切出 whole_array 和 part_youre_using。
When I do byte[] dStyleArray = buffer[0 .. *bufferSize], is D allocating a new chunk of memory and copying everything into the D-style array, or is it pointing to the already-allocated C-style array?
它在指着。 Phobos 使用相同的技巧将 C "string" 转换为 D:
https://github.com/D-Programming-Language/phobos/blob/67c95e6de21d5d627e3c57128b4d6e332c82f785/std/string.d#L208-L211
What's going on when I do dStyleArray.length = dStyleArray.length + 16? Since dStyleArray was sliced from buffer, am I allocating new memory/copying memory now? Or did I extend into buffer?
这可能不是您想要/期望的。它将在 garbage collected 内存上分配一个新块,并将内容复制到其中。它无法扩展它,因为运行时没有关于内存块的任何信息(它不管理它)。您真的要扩展缓冲区,还是要移动指针(这将在 D 中切片)?
When I do buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];, I am copying memory, right?
是的。这已降低为 memcpy。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
是的,你一开始就是这么做的 ;)
如果您只想更改数组的前 2 个元素,只需进行绑定并更改它们,它就会 "just work"。
如果你想测试这个行为,我建议你在函数下面放一个 unittest
块,这样你就可以通过给它一个指针来测试会发生什么。此外,如果您想确保没有进行任何 GC 分配,您可能需要考虑将 @nogc
放在您的函数上以静态检查它(并且 nothrow
通常也是一个好主意C函数).
检查你的代码:
byte[] dStyleArray = buffer[0 .. *bufferSize];
这看起来不错。请注意,这不会分配内存。 D 数组本质上是一个指针和一个长度,所以这一行等同于 伪代码:
struct DByteArray { byte* ptr; size_t length; }
DByteArray dStyleArray;
dStyleArray.ptr = buffer;
dStyleArray.length = *bufferSize;
从这里开始,访问 dStyleArray
的元素将访问 buffer
指向的相同数据,这意味着:
dStyleArray[0] = cast(byte) 0xab;
dStyleArray[1] = cast(byte) 0xbc;
也会"modify buffer
"。
更进一步:
dStyleArray.length = dStyleArray.length + 16;
增加 D 动态数组的 length
将导致重新分配。此处的 D 运行时会将 dStyleArray
切片的内存复制到新分配的内存块中。如果你想让 dStyleArray
指向第一个 byte
但有更长的 length
,你必须再次切片指针:
dStyleArray = dStyleArray.ptr[0 .. dStyleArray.length + 16];
或:
dStyleArray = buffer[0 .. *bufferSize + 16];
然后,行:
buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];
(正如你猜的那样复制内存)变得多余,因为两者指向同一个内存块。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
是的,这正是指针切片的作用。
问题
接受C风格数组作为参数,将其修改为D风格数组(包括更改长度),并return将其作为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) { ... }
在我的 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;
}
它有效,但我不确定这里到底发生了什么。我主要关心的是速度。如果我循环执行此函数,我不想不断分配新内存并来回复制其内容。
当我执行 byte[] dStyleArray = buffer[0 .. *bufferSize]
时,D 是在分配新的内存块并将所有内容复制到 D 样式数组中,还是指向已分配的 C 样式数组?
当我执行 dStyleArray.length = dStyleArray.length + 16
时发生了什么?由于 dStyleArray
是从 buffer
切分出来的,我现在要分配新的 memory/copying 内存吗?或者我扩展到 buffer
?
当我buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];
时,我是复制内存,对吗?
是否可以只"bind"将 D 样式数组转换为 C 样式数组,并通过 D 样式数组的接口访问预分配的内存?
When I do byte[] dStyleArray = buffer[0 .. *bufferSize], is D allocating a new chunk of memory and copying everything into the D-style array, or is it pointing to the already-allocated C-style array?
它只是指向它。右侧的切片运算符(概念上)与 array.pointer = &first_element; array._length = length;
相同 - 非常快速和简单的操作。 (我称它为 _length
而不是 length
顺便说一句,因为设置长度 属性 实际上可能会调用一个函数,这是下一个。)
What's going on when I do dStyleArray.length = dStyleArray.length + 16?
那将分配新的内存。当长度被扩展时,除非运行时可以证明它是安全的(或者你告诉它假设它是安全的并且它知道它来自 GC),否则该数组将被复制到一个新位置。它基本上在指针上调用 realloc()
- 虽然不是字面意思,但它与 C realloc 不兼容。
由于它来自 C,运行时只知道它不拥有内存,它以某种方式在别处管理,并且在尝试扩展时总是会分配一个新内存。如果你想通过其他方式扩展,你需要自己做。
When I do buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];, I am copying memory, right?
对,确实复制了,因为您在左侧切片。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
普通的右手切片:
auto d_array = c_array[0 .. c_array_length];
处理除长度扩展之外的所有内容。它保留指针,因此写入元素会立即影响原始内容。 (顺便说一句,因为它是共享的 C 内存,请确保在 D 仍在使用它时不要 free
它!只要你只在这个函数中使用它就可以了,但不要将切片存储在任何地方.)
如果确实需要加长,需要自己动手。我喜欢这样做的方式是对整个潜在数组进行切片,满容量,然后再次切片以获得有限的容量 window.
所以可能:
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
我做 whole_array 而不是重新切片 buffer
的原因是 D 可以为我捕获越界行为。它不会在裸指针上执行此操作,但会在切片指针上执行此操作,因为它知道最大大小作为其长度。
如果您需要扩展缓冲区,请使用正确的 C 函数来执行此操作,例如 realloc
或其他任何内容,然后再次切出 whole_array 和 part_youre_using。
When I do byte[] dStyleArray = buffer[0 .. *bufferSize], is D allocating a new chunk of memory and copying everything into the D-style array, or is it pointing to the already-allocated C-style array?
它在指着。 Phobos 使用相同的技巧将 C "string" 转换为 D: https://github.com/D-Programming-Language/phobos/blob/67c95e6de21d5d627e3c57128b4d6e332c82f785/std/string.d#L208-L211
What's going on when I do dStyleArray.length = dStyleArray.length + 16? Since dStyleArray was sliced from buffer, am I allocating new memory/copying memory now? Or did I extend into buffer?
这可能不是您想要/期望的。它将在 garbage collected 内存上分配一个新块,并将内容复制到其中。它无法扩展它,因为运行时没有关于内存块的任何信息(它不管理它)。您真的要扩展缓冲区,还是要移动指针(这将在 D 中切片)?
When I do buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];, I am copying memory, right?
是的。这已降低为 memcpy。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
是的,你一开始就是这么做的 ;)
如果您只想更改数组的前 2 个元素,只需进行绑定并更改它们,它就会 "just work"。
如果你想测试这个行为,我建议你在函数下面放一个 unittest
块,这样你就可以通过给它一个指针来测试会发生什么。此外,如果您想确保没有进行任何 GC 分配,您可能需要考虑将 @nogc
放在您的函数上以静态检查它(并且 nothrow
通常也是一个好主意C函数).
检查你的代码:
byte[] dStyleArray = buffer[0 .. *bufferSize];
这看起来不错。请注意,这不会分配内存。 D 数组本质上是一个指针和一个长度,所以这一行等同于 伪代码:
struct DByteArray { byte* ptr; size_t length; }
DByteArray dStyleArray;
dStyleArray.ptr = buffer;
dStyleArray.length = *bufferSize;
从这里开始,访问 dStyleArray
的元素将访问 buffer
指向的相同数据,这意味着:
dStyleArray[0] = cast(byte) 0xab;
dStyleArray[1] = cast(byte) 0xbc;
也会"modify buffer
"。
更进一步:
dStyleArray.length = dStyleArray.length + 16;
增加 D 动态数组的 length
将导致重新分配。此处的 D 运行时会将 dStyleArray
切片的内存复制到新分配的内存块中。如果你想让 dStyleArray
指向第一个 byte
但有更长的 length
,你必须再次切片指针:
dStyleArray = dStyleArray.ptr[0 .. dStyleArray.length + 16];
或:
dStyleArray = buffer[0 .. *bufferSize + 16];
然后,行:
buffer[0 .. dStyleArray.length] = dStyleArray[0 .. dStyleArray.length];
(正如你猜的那样复制内存)变得多余,因为两者指向同一个内存块。
Is it possible to just "bind" a D-style array to a C-style array, and access pre-allocated memory through the D-style array's interface?
是的,这正是指针切片的作用。