【问题标题】:Does Swift not work with function pointers?Swift 不能使用函数指针吗?
【发布时间】:2014-07-28 02:33:19
【问题描述】:

我正在尝试在 Swift 中使用 C 库,但我无法调用任何将函数指针作为参数之一的函数。例如,我尝试在 Swift 中使用的部分 lua.h 文件如下所示:

LUA_API void  (lua_setuservalue) (lua_State *L, int idx);


typedef int (*lua_CFunction) (lua_State *L);

LUA_API void  (lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
                       lua_CFunction k);

我使用桥接头来访问库,并且从我的 Swift 代码中我可以毫无问题地调用 lua_setuservalue。但是,如果我尝试调用 lua_callk,我会得到“使用未解析的标识符 'lua_callk'”。如果我从 lua_callk 的声明中删除函数指针,我将不再收到此错误。非常感谢任何帮助。

【问题讨论】:

标签: ios c xcode lua swift


【解决方案1】:

此答案指的是早期版本的 Swift 语言,可能不再可靠。

虽然 C 函数指针在 Swift 中可用,但您仍然可以使用作为块传递给 C 函数的 swift 闭包。

这样做需要 C 中的一些“填充”例程来获取块并将其包装在 C 函数中。下面演示了它是如何工作的。

斯威夫特:

func foo(myInt: CInt) -> CInt {
    return myInt
}

var closure: (CInt) -> CInt = foo;

my_c_function(closure)

C:

void my_c_function(int (^closure)(int))
{
    int x = closure(10);
    printf("x is %d\n", x);
}

当然,您选择对封盖做什么,以及如何存储和召回以供使用取决于您。但这应该给你一个开始。

【讨论】:

  • 那么有没有一种直接的方法可以将闭包从 C 代码转换为函数指针?就像说我有一些中间 C 代码接受一个闭包作为它的参数之一,我想调用接受函数指针的原始 lua 函数。有没有办法做到这一点?
  • 这真的取决于你想做什么。顺便说一句,在不知道其实现细节的情况下尝试将闭包指针转换为函数是很危险的……如果您要传递的只是一两个闭包,则可以创建一个保存的 C 填充程序闭包作为指针,以及调用该闭包的 C 函数(传递给 lua)。有很多方法可以给这只猫剥皮。对不起,我不能再帮你了。
  • 不,这非常有帮助,谢谢。我将把它标记为正确答案,因为我认为它与我们现在将要得到的解决方案一样接近。我会祈祷 Swift 将来会支持函数指针。
【解决方案2】:

Apple 从 beta 3 开始提供函数指针,但它们只能被引用而不是被调用。

Using Swift with Cocoa and Objective-C

函数指针

C 函数指针以 CFunctionPointer<Type> 的形式导入 Swift,其中 Type 是 Swift 函数类型。例如,在 C 中具有 int (*)(void) 类型的函数指针 导入 Swift 为 CFunctionPointer<() -> Int32>

Beta 3 Release Notes (PDF)

函数指针现在也被导入,可以被引用和传递。然而, 您不能调用 C 函数指针或将闭包转换为 C 函数指针类型。

【讨论】:

    【解决方案3】:

    在 Apple documentation 中注意到 C function pointers are not imported in Swift

    【讨论】:

    • C function pointers are imported into Swift as closures with the C function pointer calling convention, denoted by the @convention(c) attribute. For example, a function pointer that has the type int (*)(void) in C is imported into Swift as @convention(c) () -> Int32. If the type of the value pointed to by a C pointer cannot be represented by Swift, as is the case with an incomplete struct type, the pointer is imported as an OpaquePointer.
    【解决方案4】:

    Swift 3.1 开始,可以像这样调用作为函数指针的任意地址:

    let fakeIMP = unsafeBitCast(0x1e233d1d0, to: IMP.self)
    unsafeBitCast(fakeIMP,to:(@convention(c)()->Void).self)()
    

    假设这个^特定的调用签名:

    void cFunction();
    

    【讨论】:

    • 访问参数(在我已经获得指针并使用您的技术快速调用的目标 c 函数内部)会导致内存崩溃(EXC_BAD_ACCESS)。如何传入和使用参数?
    • 使用@convention(c),请在此处查看我的答案以获取详细信息stackoverflow.com/a/43714950/5329717
    • 我的函数指针指向一个全局的 Objective-C 函数,而不是一个方法。这会改变事情吗?
    • @Div 在纯 Objective C 中没有函数。Objective-C 方法总是在类范围内定义为类实例方法或类静态方法。也许您的意思是带有参数的 C 函数。如果您使用所有详细信息创建自己的问题,那么解决您的问题会更容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 2014-08-13
    相关资源
    最近更新 更多