【问题标题】:Representing NULL Function Pointers to C Functions in Swift在 Swift 中表示指向 C 函数的 NULL 函数指针
【发布时间】:2016-04-28 13:52:11
【问题描述】:

考虑私有但排序的 Cocoa C 函数 _NSLogCStringFunction()_NSSetLogCStringFunction()_NSLogCStringFunction()NSLog() 返回一个指向 Objective-C 运行时幕后使用的 C 函数的函数指针,_NSSetLogCStringFunction() 允许开发人员指定自己的 C 函数进行日志记录。关于这两个函数的更多信息可以在this Stack Overflow questionthis WebObjects support article找到。

在 C 中,我可以传入一个指向 _NSSetLogCStringFunction() 的 NULL 函数指针:

extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL));

_NSSetLogCStringFunction(NULL); // valid

但是,当我尝试在纯 Swift 中执行此操作时遇到了一些问题:

/// Represents the C function signature used under-the-hood by NSLog
typealias NSLogCStringFunc = (UnsafePointer<Int8>, UInt32, Bool) -> Void

/// Sets the C function used by NSLog
@_silgen_name("_NSSetLogCStringFunction")
func _NSSetLogCStringFunction(_: NSLogCStringFunc) -> Void

_NSSetLogCStringFunction(nil) // Error: nil is not compatible with expected argument type 'NSLogCStringFunc' (aka '(UnsafePointer<Int8>, UInt32, Bool) -> ()')

如果我尝试用unsafeBitCast 绕过这个编译时警告,我的程序就会因为EXC_BAD_INSTRUCTION 而崩溃(正如预期的那样,因为签名错误):

let nullPtr: UnsafePointer<Void> = nil
let nullFuncPtr = unsafeBitCast(nullPtr, NSLogCStringFunc.self)
_NSSetLogCStringFunction(nullFuncPtr) // crash

如何在 Swift 中将 NULL 函数指针表示为 (void *)(void(*)(const char *, unsigned, BOOL))/(UnsafePointer&lt;Int8&gt;, UInt32, Bool) -&gt; Void

【问题讨论】:

  • 大声笑,无论出于何种原因立即投反对票 - 甚至没有时间阅读整个问题。
  • @luk2302 猜猜我有一个粉丝 :) 这对我来说是一个新纪录,44 秒内 -1。

标签: c swift function-pointers iphone-privateapi


【解决方案1】:

(Objective-)C 声明的 Swift 映射

extern void _NSSetLogCStringFunction(void(*)(const char*, unsigned, BOOL));

public func _NSSetLogCStringFunction(_: (@convention(c) (UnsafePointer<Int8>, UInt32, ObjCBool) -> Void)!)

最简单的解决方案是将 Objective-C extern 声明到一个 Objective-C 头文件中并包含它 来自桥接头。

或者,在纯 Swift 中应该是

typealias NSLogCStringFunc = @convention(c) (UnsafePointer<Int8>, UInt32, ObjCBool) -> Void

@_silgen_name("_NSSetLogCStringFunction")
func _NSSetLogCStringFunction(_: NSLogCStringFunc!) -> Void

在任何一种情况下,函数参数都是隐式展开的可选参数, 您可以使用nil 调用它。示例:

func myLogger(message: UnsafePointer<Int8>, _ length: UInt32, _ withSysLogBanner: ObjCBool) -> Void {
    print(String(format:"myLogger: %s", message))
}

_NSSetLogCStringFunction(myLogger) // Set NSLog hook.
NSLog("foo")
_NSSetLogCStringFunction(nil) // Reset to default.
NSLog("bar")

输出:

我的记录器:foo 2016-04-28 18:24:05.492 编 [29953:444704] 酒吧

【讨论】:

  • 呃,真的吗?我需要做的就是将Bool 更改为ObjCBool? -_- Swift 中有太多的 Bool 类型。谢谢马丁。
  • @JAL:还有@convention(c) 和隐式展开的参数。
  • 其实我觉得ObjCBool 是不需要的。看起来我只是错过了 @convention(C) 和隐式展开的参数。将Bool 与其他两个一起使用似乎可行。你看到同样的东西吗?
  • @JAL:可能是这样,但 ObjCBool 是 Objective-C 声明的“生成接口”显示的,所以 I 会使用它。跨度>
  • @JAL:我在这里写了一些关于各种布尔值的文章:stackoverflow.com/a/33667761/1187415BOOL 通常映射到 Bool,但并非总是如此。我不确定这是否适用于函数指针。 – 但根据我的经验,“生成的界面”显示了正确的映射。
猜你喜欢
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多