【问题标题】:C-style uninitialized pointer passing in Apple Swift?在 Apple Swift 中传递 C 风格的未初始化指针?
【发布时间】:2014-06-06 20:29:51
【问题描述】:

我正在尝试在 Apple Swift 中实现一些 AES256 加密例程,以玩弄 ObjC、C 和 Swift 代码和数据类型之间的互操作性,但遇到了一些问题,希望有人能提供一些建议关于我忽略的事情。

正如大多数人所熟悉的,常见的 C 样式模式是声明一个未初始化的指针,然后将其传递给一个函数,其中函数调用 malloc() 并将指针指向它;函数调用完成后,指针指向新创建的对象。 Common Crypto 库在某些地方使用它;最值得注意的是,当创建一个新的 CCCryptor 对象时(实际上是一个幕后结构,看起来,类型定义为 CCCryptorRef 以获得不透明的引用) - 调用 CCCryptorCreate() 的最后一个参数就是这样一个指针,并且应该在函数调用结束,包含指向 CCCryptorRef 的指针。

Swift 对此提出了质疑 - 变量不能未初始化,它们要么总是有值要么为零(/可选),因此我在这里遇到了一些问题。以下内容不起作用,因为 CCCryptorCreate (正确地)表现得好像我只是将 nil 作为最后一个参数传递,我就是这样:

var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?> = nil
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
  CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256), 
  nil, myCryptorRef)

但是你也不能像这样声明它为可选的:

var myCryptorRef: CMutablePointer<Unmanaged<CCCryptorRef>?>?

或者作为非指针类型:

var myCryptoRef: Unmanaged<CCCryptorRef>?
CCCryptorCreate(CCOperation(kCCEncrypt), CCAlgorithm(kCCAlgorithmAES128),
  CCOptions(kCCOptionECBMode), seedData.bytes(), UInt(kCCKeySizeAES256), 
  nil, &myCryptorRef)

由于 CCCryptorCreate 期望的是指向 CCCryptorRef 的未初始化指针或已经 malloc() 的 CCCryptorRef,因此尝试将尚未初始化的对象的地址传递给它并不像您预期​​的那样顺利.

所以,归结为:在调用 CCCryptorCreate 之前,任何人都可以想出一种方法来初始化 CCCryptor 结构(通过命名结构内的所有变量来命名结构 init 的 Swift 标准方法似乎不起作用) ,或者一些替代结构,可以让我保留未初始化指针的 C 概念以便以这种方式使用?感谢您提出的任何建议。

为了清楚起见,来自 cmets:Swift 将对 CCCryptorCreate() 的调用解释如下:

CCCryptorCreate(op: CCOperation, alg: CCAlgorithm, options: CCOptions, 
  key: CConstVoidPointer, keyLength: UInt, iv: CConstVoidPointer, 
  cryptorRef: CMutablePointer<Unmanaged<CCCryptor>?>)

对我尝试过的其他一些事情进行了额外的编辑:为了真正荒谬,我尝试了以下方法,但它也没有奏效(调用 fromOpaque 时的 EXC_BAD_ACCESS):

var someMem = malloc(UInt(sizeof(CCCryptor)))
var crashTime = Unmanaged<CCCryptor>.fromOpaque(someMem)

此外,CCCryptor 或 CCCryptorRef 提到的每个地方,我都尝试过其中一个 - 在 CommonCrypto/CommonCryptor.h 中,CCCryptorRef 是这样定义的:

typedef struct _CCCryptor *CCCryptorRef

因此,虽然现有的 Objective-C 代码示例使用 CCCryptorRef,但我也一直在尝试。

【问题讨论】:

  • 如果您为CCCryptorCreate 添加了什么 Swift 类型(又名函数签名)会有所帮助,我不熟悉该 API。特别是它最后一个参数的类型是什么?

标签: swift


【解决方案1】:

试试这个:

var myCryptor: Unmanaged<CCCryptor>?

CCCryptorCreate( .... , &myCryptor )

来自Using Swift with Cocoa and Objective-C

如果你声明了这样一个函数:

func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }

您可以通过以下任何一种方式调用它:

var x: Float = 0.0 
var p: CMutablePointer<Float> = nil 
var a: Float[] = [1.0, 2.0, 3.0] 
takesAMutablePointer(nil) 
takesAMutablePointer(p) 
takesAMutablePointer(&x) 
takesAMutablePointer(&a)

您还应该检查 this 并将 Unmanaged 引用转换为托管的东西。

【讨论】:

  • CCCryptorCreate 返回时没有任何错误代码,但 myCryptor!.takeUnretainedValue() 之后会导致 EXC_BAD_ACCESS(code=1, address=0x20) 尝试保留不存在的对象。在调用 CCCryptorCreate 后立即进行调试,lldb 无法显示 myCryptor 的值 - 它显示为“(_value = )。我在代码的前面使用不同的函数(和 CC_SHA256_CTX 结构)遇到了这个问题,并且是只能通过手动创建结构来分配内存来解决它 - 但是我似乎无法手动分配 CCCryptor 结构。
  • 嗯。使用 if 来检查它是否为 nil。如果您在使用时遇到崩溃,这是第一件事!很抱歉,除此之外我无法为您提供太多帮助。我个人没有编译器,编译器仍处于测试阶段,有时会做一些奇怪的事情(据我听到很多人说),而且我不知道那个特定的 API。
  • 但我怀疑存在内在问题。换句话说,Swift 导入该函数的方式可能是错误的。不幸的是,我没有编译器,也没有找到任何关于 UnmanagedCMutablePointer 实际实现的文档。我认为它们是结构,但我无权访问标题,因此我无法检查很多内容。如果一切都不像普通指针那么大(在 sizeof 意义上),那么 API 的翻译方式就是错误的。
  • 更新了关于 CCCryptor/CCCryptorRef 问题的帖子。
  • 嗯。感谢您接受答案,即使它不是真正的解决方案。我确实相信,除非编译器出现问题,否则这是正确的方法。但是我没有编译器,你说它不起作用。所以...如果您在这些论坛上找不到解决方案,您可能希望将其发布到 Apple 论坛并提交错误报告。
【解决方案2】:

这是一个适用于 beta 3 的示例,使用来自 librabbitmq 的类型:

let envelopePtr = UnsafePointer<amqp_envelope_t>.alloc(1)
reply = amqp_consume_message(connection, envelopePtr, nil, 0)
let envelope = envelopePtr.memory

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2011-04-10
    • 1970-01-01
    相关资源
    最近更新 更多