c - 如何在 Swift 中复制指向数组的指针?

标签 c swift pointers unsafe-pointers

我基本上试图将 C 结构包装在 Swift 类中。

Swift 类有一个 C 结构类型的实例属性。

C 结构包含多个 const char * 类型的属性。

为了给结构赋值,我为每个属性编写了 getter 和 setter:

public class MyClass: NSObject {
    private var configuration = c_structure_config()
}
// Function of MyClass
// f.ex. on "registrationUri:"
private(set) public var registrationUri: String {
    get {
        return String(cString: configuration.reg_uri)
    }
    set {
        if (configuration.reg_uri != nil) {
            configuration.reg_uri.deallocate()
        }
        let maxLength = newValue.count + 1 // +1 for NULL
        var buffer: [CChar] = [CChar](UnsafeMutableBufferPointer<Int8>.allocate(capacity: maxLength))
        guard newValue.getCString(&buffer, maxLength: maxLength, encoding: .utf8) == true else {
            fatalError("Could not allocate memory for Account Config reg uri")
        }
        // "configuration" is the instance property (see above)
        // reg_uri is of type char const *
        configuration.reg_uri = UnsafePointer<Int8>(buffer)
    }
}

但是,这种方法会导致奇怪的崩溃和错误报告,提示指针重叠范围( fatal error :UnsafeMutablePointer.initialize重叠范围)。

我知道每当设置字符串时我都会释放和分配内存,但这可能不是很有效。不过到目前为止我还没有找到更好的解决方案。

这里出了什么问题(或者这是对的,我做了一个错误的假设,我必须在其他地方搜索)?

最佳答案

您的解决方案存在一些问题。

首先,使用String.count来计数来获取底层C缓冲区的大小是不明智的。原因是 String.count 返回字符串的实际字符数,而不是用于表示它的字节数。并非所有字符都适合 Int8(又名 CChar)的 256 位。因此,如果您尝试使用非 ASCII 字符设置属性,您的代码可能会崩溃。最好使用 String.utf8CString 属性,它返回 CChar 的连续数组。

其次,由于您的缓冲区是在 setter 内分配的,因此当您的 setter 返回时,它将被释放(Swift 数组是值类型的实例,其生命周期受堆栈约束)。这意味着当您的 setter 返回时,与 buffer 的基址对应的指针实际上已失效。我怀疑这就是您报告的错误在运行时发生的原因。

最后,请不要在守卫和 if 语句中测试 true

这是更正后的版本:

var registrationUri: String {
  get {
    return String(cString: reg_uri)
  }
  set {
    if (reg_uri != nil) {
      reg_uri.deallocate()
    }

    newValue.withCString { cString in
      // No need to add 1, newValue.utf8CString already has the correct buffer capacity.
      let capacity = newValue.utf8CString.count
      let buffer: UnsafeMutablePointer<Int8> = .allocate(capacity: capacity)
      buffer.assign(from: cString, count: capacity)
      reg_uri = UnsafePointer(buffer)
    }
  }
}

// ...

myInstance.registrationUri = "こんいちは"
print(myInstance.registrationUri)
// Prints "こんいちは"

关于c - 如何在 Swift 中复制指向数组的指针?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57058778/

相关文章:

c - Kochan InsertString 段错误

c - 是否应该将 "initCount"变量声明为 "volatile"?

xcode - Swift 泛型函数在测试中无法编译

swift - 将 AVSpeechSynthesizer 用于中文拼音

c - 指向结构内部的结构指针的空指针而不取消引用它

c - 在 C 中传递二维数组

c - 在不同的头文件中定义 ARGS 有什么用?

c - 如何在 linux 中获取套接字的 tcp 窗口大小?

swift - 我如何使用 RX 应用宽限时间?

ios - 双指针在 Objective-C 中是什么意思?