0

The statfs struct in C has these char array members:

char f_mntonname[MNAMELEN];    /* directory on which mounted */
char f_mntfromname[MNAMELEN];  /* mounted file system */

The Swift type for these arrays in the Darwin.sys.mount module is a tuple with 90 elements:

public var f_mntonname: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8,
                         ...
                         Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)

Another question about Converting a C char array to a String has an answer with code that I use twice in this example:

import Darwin.sys.mount
var vols: UnsafeMutablePointer<statfs>?
let count = getmntinfo(&vols, 0)    
if let volsarray = vols, count > 0 {
    for i in 0 ..< count {
        var vol = volsarray[Int(i)]
        let mntOnName = withUnsafePointer(to: &vol.f_mntonname) {
            $0.withMemoryRebound(to: UInt8.self,
                                 capacity: MemoryLayout.size(ofValue: vol.f_mntonname)) {
                String(cString: $0)
            }
        }
        let mntFromName = withUnsafePointer(to: &vol.f_mntfromname) {
            $0.withMemoryRebound(to: UInt8.self,
                                 capacity: MemoryLayout.size(ofValue: vol.f_mntfromname)) {
                String(cString: $0)
            }
        }
        print("on \(mntOnName)  from \(mntFromName)")
    }
}

To avoid repeating the code twice, I refactored the conversion code into the function below, but passing &vol.f_mntonname to it won't compile, and I can't see a way to fix the problem by using a different type for the first argument.

func charArrayToString(_ array: UnsafePointer<Int8>, capacity: Int) -> String {
    return array.withMemoryRebound(to: UInt8.self, capacity: capacity) {
        String(cString: $0)
    }
}

var a = (Int8(65), Int8(66), Int8(67))
print(charArrayToString(&a, capacity: 3)) // doesn't compile

The compiler complains about call to charArrayToString:
    Cannot convert value of type '(Int8, Int8, Int8)' to expected argument type 'Int8'

It also complains when I pass a instead of &a:
    Cannot convert value of type '(Int8, Int8, Int8)' to expected argument type 'UnsafePointer<Int8>'

1 Answer 1

2

You are trying to pass a pointer to a tuple as a point to a Int8. Instead you need to pass a pointer to the first element of the tuple. For example define the function:

func charPointerToString(_ pointer: UnsafePointer<Int8>) -> String
{
   return String(cString: UnsafeRawPointer(pointer).assumingMemoryBound(to: CChar.self))
}

(This function is adapted from and example in Apple's UnsafeRawPointer Migration). Use this in your code to shorten your two let's passing a pointer to the first tuple element:

let mntOnName = charPointerToString(&vol.f_mntonname.0)
let mntFromName = charPointerToString(&vol.f_mntfromname.0)

However, despite that following the code in Apple's document it seems a bit overkill, you can also just:

let mntOnName = String(cString: &vol.f_mntonname.0)
let mntFromName = String(cString: &vol.f_mntfromname.0)

(All code tested using Xcode 8.2.1.)

HTH

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.