数组元素解引用和寻址 - &buffer[index] - 在 Swift 中工作吗?

Posted

技术标签:

【中文标题】数组元素解引用和寻址 - &buffer[index] - 在 Swift 中工作吗?【英文标题】:Does array element dereferencing and addressing - &buffer[index] - work in Swift? 【发布时间】:2015-09-09 07:54:53 【问题描述】:

我正在编写一个 Swift 应用程序,为此我需要使用 C 函数从套接字进行一些网络缓冲。 Swift 通过桥接头导入这些函数,它们需要缓冲区指针参数。

这两个功能是有效的:

read(Socket s, void *buf, int num);
write(Socket s, const void *buf, int num);

Swift 编译器指出这些函数需要UnsafePointer<Void>。我有一些[UInt8] 类型可以保存我的可写数据并接受我的可读数据。 Swift 编译器不会抱怨我写的东西,但是我相信下面的代码并没有按照我在 C 语法中的预期做。

这是我的阅读循环:

var index: Int32 = 0    
while index < length 
    var toRead = length - index
    if toRead > bufferSize 
        toRead = bufferSize
    

    // Read into my buffer ([Int8]), starting at element `hasRead`
    let justRead: Int32 = read(s, &buffer[Int(index)], toRead)
    index += justRead

还有我的写循环:

var index: Int32 = 0
while index < length 
    var toWrite: Int32 = length - index
    if toWrite > bufferSize 
        toWrite = bufferSize
    

    // Write from my buffer ([Int8]), starting at element `index`
    let wrote = write(s, &buffer[Int(index)], toWrite)
    index += wrote

我的问题是:&amp;buffer[Int(index)] 在这种情况下是传递(可变)数组的正确方法吗? (即,它是否在执行我期望 C 使用该语法执行的操作 - 获取数组字节的第 index 个元素的地址)。如果没有,我如何正确地将我的[UInt8] 传递给桥接的 C 函数?

【问题讨论】:

这里讨论了一个类似的问题(使用计算属性而不是下标):***.com/questions/31232190/…。我假设相同的推理在这里是有效的,并且您的代码应该按预期工作。 @MartinR 这个概念是有效的,但我认为假设传入的指针可用于访问数组中除了它指向的值之外的任何值是不安全的。跨度> @jtbandes:你是对的。我误读了这个问题。 【参考方案1】:

我建议小心&amp;buffer[Int(index)]。目前尚不清楚从文档中可以保证做什么。当然,它可以用来修改数组的单个元素,但我认为你不应该依赖这个指针的指针运算(所以你不应该将它传递给这样的函数)。

但是,您可以/应该使用的是withUnsafeMutableBufferPointer() (apparently missing from docs currently)(或非可变版本)。这保证使用 UnsafeMutableBufferPointer 调用提供的闭包到连续存储,您可以使用它来读取和写入数组。你可能想使用它的baseAddress

(另请注意,除了 Array 之外,Swift 还有一个 ContiguousArray,它的存储保证是连续的,所以你可能会看到比 Array 稍微好一点的性能,因为你知道无论如何你都会要求它提供一个连续的缓冲区。但是不要在这里对性能做太多假设——它没有很好的记录!我怀疑你是否需要在实践中使用 ContiguousArray。)

【讨论】:

上次我检查时,数组索引以下列方式与 pass-by-inout 一起工作。编译器使用索引 getter 将索引集合中的元素检索到临时对象中。然后将临时对象的地址传递给被调用者。在被调用者返回后,索引设置器在集合上调用 - 现在可能已修改 - 临时的。 是的,这听起来就像我所看到的一样。这也意味着didSets(我猜sets)无论被调用者是否修改值都会被调用。 &amp;buf[0] 上的指针运算似乎在一个简单的测试中有效,但我认为它不能保证在所有情况下都有效(可能是未定义的行为)。 This page 也有一些有用的信息。 如果我要使用可从withUnsafeMutableBufferPointer 访问的指针的baseAddress,我假设我需要调用advancedBy: 以将指针推进到正确的索引...虽然我完全理解它,但有时文档的不完整性可能是一个很大的障碍! @Ephemera 您可以简单地使用 + 运算符(它适用于 Swift 中的 UnsafePointer)。【参考方案2】:

你可以:

read(s, &buffer + Int(index), toRead)

我认为&amp;buffer[Int(index)] 不安全,正如this QA 中所讨论的那样

【讨论】:

以上是关于数组元素解引用和寻址 - &buffer[index] - 在 Swift 中工作吗?的主要内容,如果未能解决你的问题,请参考以下文章

buffer & cache

一级指针,二级指针,指针数组,数组和指针

《斯坦福大学:编程范式》第三节:* 与&的技巧大端与小端最小寻址单位

《C程序设计语言》笔记 指针与数组

面试中常被问到C/C++中数组,指针和引用的区别

《数据结构》之数组结构和链表