How to pass swift String to c function in Swift 5

I want to pass swift String to c function in swift 5 .

String in swift

var key = "zxcvbnmqwertyui"
var error = "noerror"

C function declaration

extern KeyRef key(char* p0, char** p1);

C Function declaration in swift

public func key(_ p0: UnsafeMutablePointer<Int8>!, _ p1: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!) -> KeyRef

Question : How can i pass swift string (i.e key and error) to c function (i.e key ) ?

Hello!

It looks like parts of this answer may have been discussed by @eskimo and @John_McCall on another thread, but I also thought I would provide some insight here in case it helped.

On the C side of the codebase setup the C files and expose the needed functions to Swift using a bridging header. If you start a Swift project and add C or ObjC files to it Xcode will ask if you want to generate a bridging header for your project.

C_String.c

void key_function(char *p0, char **p1) {
    printf("po: %s \n", p0);
    printf("p1: %s \n", *p1);
}

As mentioned above, the bridging header is the place to expose C functions, or C header files with many functions, to Swift.

SwiftString-Bridging-Header.h

// Add C Function here or optionally add C headers here.
extern void key_function(char *p0, char **p1);

In the Swift side of the codebase I am suggesting working with an NSString to provide a NULL terminated UTF8 representation of the string that UnsafeMutablePointer can use to create CChar's from and then send over to the key_function() in C.

Main.swift

// Swift Strings
var key: NSString = "zxcvbnmqwertyui"
var error: NSString = "noerror"

// Convert the Swift strings to CChars (or Int8) that map to 
var key_p0 = UnsafeMutablePointer<CChar>(mutating: key.utf8String)
var error_p1 = UnsafeMutablePointer<CChar>(mutating: error.utf8String)

// Pass the character pointers over to the key_function() function in C.
key_function(key_p0, &error_p1)

I hope this helps!

I think you should also use withExtendedLifetime on the two strings to make sure they aren't prematurely deallocated. Those UnsafeMutablePointer will not retain the strings.

1 Like

@agnosticdev Thanks for replying , your solution worked .

1 Like

@shivam201312 no problem at all. Glad to help out!

hello, you can also convert String to UnsafeMutablePointer by using pure swift.

var key = "some strings here"
var key_p0 = UnsafeMutablePointer<CChar>(mutating: key.cString(using: .utf8))

Here are APIs from Apple Documentation

    /// The C 'char' type.
    ///
    /// This will be the same as either `CSignedChar` (in the common
    /// case) or `CUnsignedChar`, depending on the platform.
    public typealias CChar = Int8
    /// Returns a representation of the string as a C string
    /// using a given encoding.
    public func cString(using encoding: String.Encoding) -> [CChar]?
    /// Creates a mutable typed pointer referencing the same memory as the given
    /// immutable pointer.
    ///
    /// - Parameter other: The immutable pointer to convert.
    public init(mutating other: UnsafePointer<Pointee>)

you can also convert String to UnsafeMutablePointer by using pure
Swift.

The code you posted is not safe. When you build it with a modern version of Swift (I’m using Xcode 12.0, that is, Swift 5.3) you get this warning:

…/main.swift:5:14: warning: initialization of 'UnsafeMutablePointer<CChar>' (aka 'UnsafeMutablePointer<Int8>') results in a dangling pointer
var key_p0 = UnsafeMutablePointer<CChar>(mutating: key.cString(using: .utf8))
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See The Peril of the Ampersand for my explanation as to why.

Some Swift engineers spoke about issues at WWDC 2020 and I strongly encourage you to watch their videos:

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

5 Likes

Okay, i will focus on it. Thank you for your correct.