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?

GlorySaber
  • 367
  • 2
  • 12
  • 1
    C arrays are imported to Swift as *tuples*, which makes them inconvenient to use. Does this help http://stackoverflow.com/questions/27461904/convert-an-string-to-an-array-of-int8 ? – Martin R Aug 06 '16 at 02:47
  • 1
    Btw, you usually would import a h-file, not a c-file. – Martin R Aug 06 '16 at 02: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. – GlorySaber Aug 06 '16 at 03:00

1 Answers1

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.

Community
  • 1
  • 1
OOPer
  • 47,149
  • 6
  • 107
  • 142
  • 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)) – GlorySaber Aug 06 '16 at 04:00
  • @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)`. – OOPer Aug 06 '16 at 04:23
  • @StephenKac, OK, I will append Swift 3 version of my code. – OOPer Aug 06 '16 at 04:25
  • @MartinR, thanks. I think my code works well about NUL-terminating manually. But your suggestion seems to be quite better. – OOPer Aug 06 '16 at 07:41
  • 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. – GlorySaber Aug 06 '16 at 16:23
  • That's another "I cannot" reproduce, and in this case, I assume we use the same version of Xcode, so, how do you "print it to the screen" ? Show your code. – OOPer Aug 06 '16 at 19:55
  • Oops, sorry it was my fault. I capitalized Dog. My Bad. – GlorySaber Aug 07 '16 at 19:25