Port C code with a lot of typecasts to Swift

Swift allows you to call existing C library calls and system calls normally. This is correct from the perspective of making good use of past assets, but since Swift is more type-strict than C, it is not uncommon to have trouble calling C functions.

This time, I rewrote the third argument start_routine of pthread_create from the C function to the closure of Swift. I hope it helps you to see what happens to the code cast in C in Swift.

(Because I am a beginner in Swift, please let me know if there are any mistakes)

Prerequisite knowledge

pthread_create creates a new thread and passes the function pointer of the function to be executed in the new thread with the third argument start_routine. Function arguments and return values are void *, so if you want to use different types of arguments and return values, you need to typecast both the caller and the callee.

It's a C-like idea to make anything void *, but of course it doesn't go well with Swift.

Original C source code

This time, I wanted to use a function that takes ʻintandchar ** as arguments and returns ʻint (in short, it's a main function) from pthread_create, so I used a wrapper function for that. I wrote it in C.

void *pthread_main_routine(void *_arg)
{
    void **arg = (void **)_arg;
    int argc = (int)arg[0];
    char **argv = (char**)arg[1];
    void *retval = (void *)(long)orig_main(argc, argv);
    return retval;
}

This was called on the Swift side as follows.

    var thread_arg = [
        UnsafeMutablePointer<Void>(bitPattern: args.pointers.count-1),
        UnsafeMutablePointer<Void>(args.pointers)
    ]
    pthread_create(&thread, nil, pthread_main_routine, &thread_arg)

I tried to rewrite it with Swift closure

It worked in the above code as well, but I tried replacing the C function with a Swift closure for various reasons.

    typealias VoidPtr = UnsafeMutablePointer<Void>
    typealias VoidPtrArray = [UnsafeMutablePointer<Void>]
    typealias CharPtrArray = [UnsafeMutablePointer<CChar>]
    let thread_arg = [
        unsafeBitCast(args.pointers.count-1, VoidPtr.self),
        unsafeBitCast(args.pointers, VoidPtr.self),
    ]
    pthread_create(&thread, nil, {_arg in
        let arg = unsafeBitCast(_arg, VoidPtrArray.self)
        let argc = Int32(unsafeBitCast(arg[0], Int.self))
        let argv = unsafeBitCast(arg[1], CharPtrArray.self)
        let retval = unsafeBitCast(Int(orig_main(argc, argv)), VoidPtr.self)
        return retval
        }, unsafeBitCast(thread_arg, VoidPtr.self))

I managed to make something that works with a lot of ʻunsafeBitCast`, but the code is quite verbose and hard to read. Code that is easier to write in C should be written in C.

By the way, please note that the contents passed are slightly different depending on whether the Swift array is converted to void * or char ** to void * in the two codes.

Complaints etc.

The handling of C functions in Swift2 is not good, and only the global function name itself or closure literal can be placed in the third argument of this pthread_create. If you assign a function to a variable and give that variable as an argument, you will get a compile error as follows.

A C function pointer can only be formed from a reference to a 'func' or a literal closure

Also, don't write code that depends on the environment, even if it's a closure literal. For example, if you refer to an instance variable from within a closure, you will get a compile error as follows.

A C function pointer cannot be formed from a closure that captures context

I feel that the latter can't be helped, but what about the former? I feel like that. I hope Swift3 will be easier to handle around here.

Recommended Posts

Port C code with a lot of typecasts to Swift
[swift5] How to change the color of TabBar or the color of item of TabBar with code
Convert a string to a character-by-character array with swift
Transition to a view controller with Swift WebKit
How to get the ID of a user authenticated with Firebase in Swift
How to implement UICollectionView in Swift with code only
Add a local Swift Package to your project with Swift PM
A story addicted to toString () of Interface proxied with JdkDynamicAopProxy
A series of steps to create portfolio deliverables with Rails
How to move another class with a button action of another class.
A memo to start Java programming with VS Code (2020-04 version)
Pass C ++ char * to Swift
Wasteful processing of collections-I want to give you a chance to write good code. 5 [C # refactoring sample]
Try to imitate the idea of a two-dimensional array with a one-dimensional array
A story of connecting to a CentOS 8 server with an old Ansible
Make a C compiler to use with Rust x CLion with Docker
Sample code to unit test a Spring Boot controller with MockMvc
[With sample code] Basics of Spring JDBC to learn with Blog app
How to open a script file from Ubuntu with VS code
Make a Christmas tree with swift
[Swift] How to send a notification
To be aware of easy-to-read code
Call a C function from Swift
Convert Swift 2D array to C 2D array
A record of setting up a Java development environment with Visual Studio Code
[iOS] I tried to make a processing application like Instagram with Swift
rails c does not start and a lot of line errors appear
How to make an app with a plugin mechanism [C # and Java]
[Swift] Converts a UInt64 type integer to [UInt8]
Convert C language to JavaScript with Emscripten
Link Java and C ++ code with SWIG
[Swift 5] Implementation of membership registration with Firebase
How to call Swift 5.3 code from Objective-C
[Swift] Easy to implement modal with PanModal
Extract a part of a string with Ruby
[Swift5] How to create a splash screen
Ability to display a list of products
How to run Blazor (C #) with Docker
Connect with VS Code from a Windows client to Docker on another server
I tried to implement a function equivalent to Felica Lite with HCE-F of Android
Volume that wants to use a lot of logical operators in if statements
Send a notification to slack with the free version of sentry (using lambda)
Rails6 I want to make an array of values with a check box
[Code] Forcibly breaks through the C problem "* 3 or / 2" of [AtCoder Problem-ABC100] with Java [Code]
[Spring Boot] If you use Spring Boot, it was convenient to use a lot of util.
I tried to clone a web application full of bugs with Spring Boot
From creating a Spring Boot project to running an application with VS Code
[Swift] I already have a lot of information, but I tried to summarize the cast (as, as !, as?) In my own way.