9

I'm trying to use a C library in Swift, and I'm having trouble calling any function that takes a function pointer as one of it's arguments. For example, part of the lua.h file that I'm trying to use in Swift looks like this:

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);

I use the bridging header to get access to the library, and from my Swift code I can call lua_setuservalue without any trouble. But if I try to call lua_callk I get "use of unresolved identifier 'lua_callk'". If I remove the function pointer from the declaration for lua_callk, I no longer get this error. Any help is quite appreciated.

Mike
  • 6,285
  • 4
  • 18
  • 22
  • here is a useful ref: https://stackoverflow.com/questions/36025632/how-do-i-declare-create-and-use-method-pointers-in-swift/48213241#48213241 – J-Dizzle Jan 11 '18 at 18:00

4 Answers4

18

This answer refers to an earlier version of the Swift language and may no longer be reliable.

While C function pointers are not available in Swift, you can still use swift closures which are passed to C functions as blocks.

Doing so requires a few "shim" routines in C to take the block and wrap it in a C function. The following demonstrates how it works.

Swift:

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);
}

Of course what you choose to do with the closure, and how you store and recall it for use is up to you. But this should give you a start.

Jim Hayes
  • 2,126
  • 1
  • 15
  • 21
  • So is there a straightforward way to convert the closure into a function pointer from C code? Like say I have some intermediate C code that accepts a closure as one of it's arguments, and I want to call the original lua function that accepts a function pointer. Is there a way to do that? – Mike Jun 09 '14 at 15:30
  • That really depends on what you want to do. Off hand, it would be dangerous to try to convert the closure pointer to a function without knowing the particulars of how its implemented... If it's just one or two closures you're going to pass, you can create a C shim that saves the closure as a pointer, and C function that (that you pass into lua) that calls that closure. There are many ways to skin this cat. Sorry I can't help you any further. – Jim Hayes Jun 09 '14 at 23:05
  • No that's extremely helpful, thank you. I'm going to mark this as the correct answer since I think it's about as close to a solution as we're going to get right now. I'm going to cross my fingers that Swift gains support for function pointers in the future. – Mike Jun 11 '14 at 15:29
10

Apple has made function pointers available as of beta 3, however they can only be referenced not called.

Using Swift with Cocoa and Objective-C

Function Pointers

C function pointers are imported into Swift as CFunctionPointer<Type>, where Type is a Swift function type. For example, a function pointer that has the type int (*)(void) in C is imported into Swift as CFunctionPointer<() -> Int32>

Beta 3 Release Notes (PDF)

Function pointers are also imported now, and can be referenced and passed around. However, you cannot call a C function pointer or convert a closure to C function pointer type.

TiLogic
  • 199
  • 1
  • 2
  • 10
2

In the Apple documentation it is noted that C function pointers are not imported in Swift.

Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188
  • 1
    `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.` – MartinZ Jul 18 '21 at 02:40
2

Since Swift 3.1 an arbitrary address being a function pointer can be called like this:

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

Assuming for this^ particular call signature:

void cFunction();
Kamil.S
  • 5,205
  • 2
  • 22
  • 51
  • Accessing the parameters (inside of an objective c function which I have obtained the pointer of and using your technique have called in swift) causes a memory crash (EXC_BAD_ACCESS). How can I pass parameters in and use them? – Div May 30 '20 at 18:52
  • Using `@convention(c)`, check my answer here for details https://stackoverflow.com/a/43714950/5329717 – Kamil.S May 30 '20 at 18:57
  • My function pointer points to a global Objective-C function, rather than a method. Does that change things? – Div May 30 '20 at 19:07
  • @Div There are no functions in pure objective C. Objective-C methods are always defined in class scope either as class instance method or class static method. Perhaps you meant a C function with arguments. It would be easier to address your case if you create your own question with all the details. – Kamil.S May 30 '20 at 19:28
  • https://stackoverflow.com/questions/62108482/bidirectional-data-exchange-between-macos-bundles-swift thanks – Div May 30 '20 at 20:49