2

Currently I have three files

main.swift

var dog = Dog()

dog.age = 12
dog.name = "H" // This is the non workable code

CTester.c

#include <stdio.h>

struct Dog {
    int age;
    char name[10];
} Dog;

and C Test-Bridging-Header

#import "CTester.c"

I am trying to use the C struct in Swift, however, the Char array shows up as an array of 10 Int8 in Swift. How can I take a Swift string and assign it to the char array?

3
  • 1
    C arrays are imported to Swift as tuples, which makes them inconvenient to use. Does this help stackoverflow.com/questions/27461904/… ? Commented Aug 6, 2016 at 2:47
  • 1
    Btw, you usually would import a h-file, not a c-file. Commented Aug 6, 2016 at 2:48
  • Thanks Martin that helps me understand why its doing Tuples, also thats a great link! I may be able to use the info in there to figure out how to do what I want to do. Yes I know I should use an H file as good practice but this is such a small test that it doesn't make since. Commented Aug 6, 2016 at 3:00

1 Answer 1

4

So, you can write some extension for your Dog like this:

Swift 2

extension Dog {
    var Name: String {
        mutating get {
            return withUnsafePointer(&self.name) {namePtr in
                let charPtr = UnsafePointer<CChar>(namePtr)
                //Sorry, this code may crash here...
                return String(CString: charPtr, encoding: NSUTF8StringEncoding)!
            }
        }
        set {
            withUnsafeMutablePointer(&self.name) {namePtr in
                let charPtr = UnsafeMutablePointer<CChar>(namePtr)
                let size = sizeofValue(self.name)
                strncpy(charPtr, newValue, size - 1)
                charPtr[size - 1] = 0
            }
        }
    }
}

Swift 3(Tested with Xcode 8 beta 4)

extension Dog {
    var Name: String {
        mutating get {
            return withUnsafePointer(&self.name) {namePtr in
                let charPtr = UnsafePointer<CChar>(namePtr)
                //The result may contain the Unicode replacement character ("\u{FFFD}")
                return String(cString: charPtr)
            }
        }
        set {
            withUnsafeMutablePointer(&self.name) {namePtr in
                let charPtr = UnsafeMutablePointer<CChar>(namePtr)
                let size = sizeofValue(self.name)
                strncpy(charPtr, newValue, size - 1)
                charPtr[size - 1] = 0
            }
        }
    }
}

Seeing the linked thread in Martin R's comment, there may be some room to improve... (Especially using strlcpy reduces your code size with better safety. Please check it.)

But anyway, it works as:

dog.Name = "H"
print(dog.Name) //->H

I have found that getter of Name may crash your app... "It works" in a restriction that you store only ASCII characters.

Sign up to request clarification or add additional context in comments.

7 Comments

The getter does not seem to work for me. It prints instead the address of the String and the Type like so: (0x00000001003b2914, Unicode (UTF-8))
@StephenKac, sorry, but I cannot reproduce the same result. Don't you have any part of my code misspelled? I have checked my code both in OS X project and iOS project with Xcode 7.3.1 and works fine in both projects. I may be missing something, so I tried many things but I couldn't get anything like Unicode (UTF-8).
@StephenKac, OK, I will append Swift 3 version of my code.
@MartinR, thanks. I think my code works well about NUL-terminating manually. But your suggestion seems to be quite better.
It works when looking at it through the lldb Debugger but if you try to print it to the screen it does does not print a single character.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.