Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 将C字符数组转换为字符串_Arrays_Swift_Interop_Tuples - Fatal编程技术网

Arrays 将C字符数组转换为字符串

Arrays 将C字符数组转换为字符串,arrays,swift,interop,tuples,Arrays,Swift,Interop,Tuples,我有一个Swift程序,可以与C库进行互操作。此C库返回一个内部带有char[]数组的结构,如下所示: struct record { char name[8]; }; 定义已正确导入Swift。但是,该字段被解释为8个Int8元素的元组(键入(Int8,Int8,Int8,Int8,Int8,Int8)),我不知道如何使用Swift将其转换为字符串 没有接受Int8元组的String初始值设定项,而且似乎不可能获得指向元组第一个元素的指针(因为类型可能是异构的,这并不奇怪) 现在,我

我有一个Swift程序,可以与C库进行互操作。此C库返回一个内部带有
char[]
数组的结构,如下所示:

struct record
{
    char name[8];
};
定义已正确导入Swift。但是,该字段被解释为8个
Int8
元素的元组(键入
(Int8,Int8,Int8,Int8,Int8,Int8)
),我不知道如何使用Swift将其转换为
字符串

没有接受
Int8
元组的
String
初始值设定项,而且似乎不可能获得指向元组第一个元素的指针(因为类型可能是异构的,这并不奇怪)

现在,我的最佳想法是创建一个小型C函数,它接受指向结构本身的指针,并将
name
作为
char*
指针而不是数组返回,然后执行该操作

然而,有没有一种纯粹快捷的方法可以做到这一点呢?

试试这个:

func asciiCStringToSwiftString(cString:UnsafePointer<UInt8>, maxLength:Int) -> String
{
    var swiftString = String()  // The Swift String to be Returned is Intialized to an Empty String
    var workingCharacter:UnicodeScalar = UnicodeScalar(cString[0])
    var count:Int = 0           // An Index Into the C String Array Starting With the First Character

    while cString[count] != 0             // While We Haven't reached the End of the String
    {
        workingCharacter = UnicodeScalar(cString[count]) // Convert the ASCII Character to a Unicode Scalar
        swiftString.append(workingCharacter)             // Append the Unicode Scalar Version of the ASCII Character
        count++                                          // Increment the Index to Look at the Next ASCII Character

        if count > maxLength                            // Set a Limit In Case the C string was Not NULL Terminated
        {
            if printDebugLogs == true
            {
                swiftString="Reached String Length Limit in Converting ASCII C String To Swift String"
            }
            return swiftString
        }
    }

    return swiftString                     // Return the Swift String
}
func ascicstringtoswiftstring(cString:UnsafePointer,maxLength:Int)->String
{
var swiftString=String()//要返回的Swift字符串被初始化为空字符串
变量工作字符:UnicodeScalar=UnicodeScalar(cString[0])
var count:Int=0//C字符串数组的索引,从第一个字符开始
当cString[count]!=0//尚未到达字符串末尾时
{
workingCharacter=UnicodeScalar(cString[count])//将ASCII字符转换为Unicode标量
append(workingCharacter)//追加ASCII字符的Unicode标量版本
count++//递增索引以查看下一个ASCII字符
如果count>maxLength//设置一个限制,以防C字符串不是以NULL结尾的
{
如果printDebugLogs==true
{
swiftString=“将ASCII C字符串转换为Swift字符串时已达到字符串长度限制”
}
返回快捷键
}
}
return swiftString//返回Swift字符串
}

您可以使用Swift的可变参数语法将元组收集到数组中:

let record = getRecord()
let (int8s: Int8...) = myRecord          // int8s is an [Int8]
let uint8s = int8s.map { UInt8($0) }
let string = String(bytes: uint8s, encoding: NSASCIIStringEncoding)
// myString == Optional("12345678")

C数组
字符名[8]
作为元组导入Swift:

(Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
name
的地址与
name[0]
的地址相同,并且 Swift保留从C导入的结构的内存布局,如下所示

。。。您可以保留C中定义的结构并将其导入Swift。斯威夫特将尊重C的布局

因此,我们可以传递
record.name
的地址, 转换为
UInt8
指针,以 字符串初始值设定项。以下代码已为Swift 4.2及更高版本更新:

let record = someFunctionReturningAStructRecord()
let name = withUnsafePointer(to: record.name) {
    $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
        String(cString: $0)
    }
}
注意:假定
name[]
中的字节是有效的以NUL结尾的UTF-8序列

对于较旧版本的Swift:


我也有兴趣为自己的目的解决这个问题,所以我添加了一个新函数:

func asciiCArrayToSwiftString(cString:Int8...) -> String
{
    var swiftString = String()            // The Swift String to be Returned is Intialized to an Empty String
    var workingCharacter:UnicodeScalar = UnicodeScalar(UInt8(cString[0]))
    var count:Int = cString.count

    for var i:Int = 0; i < count; i++
    {
        workingCharacter = UnicodeScalar(UInt8(cString[i])) // Convert the Int8 Character to a Unicode Scalar
        swiftString.append(workingCharacter)             // Append the Unicode Scalar

    }

    return swiftString                     // Return the Swift String
}
结果是:


testSwiftString=test

我提出了一个解决方案,它使用反射将元组实际转换为[Int8](请参阅),然后使用fromCString…()方法将其转换为字符串

func数组四元组(元组:T)->[E]{
让反射=反射(元组)
变量arr:[E]=[]
对于0..String中的i{
var charArray=arrayForTuple(元组)作为[Int8]
var nameString=String.fromCString(UnsafePointer(charArray))
如果名称字符串==nil{
nameString=String.fromCStringRepairingIllFormedUTF8(未安全指针(charArray)).0
}
返回名称字符串
}
}

Swift 3。只使用反射。此版本在遇到空字节时停止构建字符串。测试

func TupleOfInt8sToString( _ tupleOfInt8s:Any ) -> String? {
    var result:String? = nil
    let mirror = Mirror(reflecting: tupleOfInt8s)

    for child in mirror.children {
        guard let characterValue = child.value as? Int8, characterValue != 0 else {
            break
        }

        if result == nil {
            result = String()
        }
        result?.append(Character(UnicodeScalar(UInt8(characterValue))))
    }

    return result
}

我刚刚在使用Swift 3时遇到了类似的问题。(3.0.2). 我试图在Swift中将CChar数组[CChar]转换为字符串。事实证明,Swift 3有一个字符串初始值设定项,它将采用cString

例如:

let a = "abc".cString(using: .utf8) // type of a is [CChar]
let b = String(cString: a!, encoding: .utf8) // type of b is String
print("a = \(a)")
print("b = \(b)")
导致

a=可选([97,98,99,0])

b=可选(“abc”)

请注意,字符串上的cString函数会产生一个可选的字符串。在创建b的String.init函数中使用时,必须强制展开。b也是可选的。。。这意味着两者最终都可能为零,因此也应该使用错误检查。

详细信息
  • 代码11.2.1(11B500),Swift 5.1
解决方案 …桥接头.h

Swift代码

输出
名称:str_1
类型:(Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8)
值:(72、101、108、108、111、32、119、111、114、108、100、33、0)
swift字符串:可选(“Hello world!\0”)
-----------------
姓名:stru 2
类型:(Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8,Int8)
值:(72、101、108、108、111、32、119、111、114、108、100、33、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0、0)
swift字符串:可选(“Hello world!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0”)
-----------------
姓名:str_3
类型:UnsafeMutablePointer
值:0x000000010e8c5d40
swift字符串:可选(“Hello world!”)
-----------------
姓名:str_4
类型:(UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8)
值:(72、101、108、108、111、32、119、111、114、108、100、32、0)
swift字符串:可选(“Hello world\0”)
-----------------
姓名:str_5
类型:UnsafeMutablePointer
值:0x000000010e8c5d80
swift字符串:可选(“Hello world”)
-----------------
姓名:str_6
类型
func arrayForTuple<T,E>(tuple:T) -> [E] {
    let reflection = reflect(tuple)
    var arr : [E] = []
    for i in 0..<reflection.count {
        if let value = reflection[i].1.value as? E {
            arr.append(value)
        }
    }
    return arr
}

public extension String {
    public static func fromTuple<T>(tuple:T) -> String? {
        var charArray = arrayForTuple(tuple) as [Int8]
        var nameString = String.fromCString(UnsafePointer<CChar>(charArray))
        if nameString == nil {
            nameString = String.fromCStringRepairingIllFormedUTF8(UnsafePointer<CChar>(charArray)).0
        }
        return nameString
    }
}
func TupleOfInt8sToString( _ tupleOfInt8s:Any ) -> String? {
    var result:String? = nil
    let mirror = Mirror(reflecting: tupleOfInt8s)

    for child in mirror.children {
        guard let characterValue = child.value as? Int8, characterValue != 0 else {
            break
        }

        if result == nil {
            result = String()
        }
        result?.append(Character(UnicodeScalar(UInt8(characterValue))))
    }

    return result
}
let a = "abc".cString(using: .utf8) // type of a is [CChar]
let b = String(cString: a!, encoding: .utf8) // type of b is String
print("a = \(a)")
print("b = \(b)")
extension String {
    init?(fromTuple value: Any) {
        guard let string = Tuple(value).toString() else { return nil }
        self = string
    }

    init?(cString: UnsafeMutablePointer<Int8>?) {
        guard let cString = cString else { return nil }
        self = String(cString: cString)
    }

    init?(cString: UnsafeMutablePointer<CUnsignedChar>?) {
        guard let cString = cString else { return nil }
        self = String(cString: cString)
    }

    init? (cString: Any) {

        if let pointer = cString as? UnsafeMutablePointer<CChar> {
            self = String(cString: pointer)
            return
        }

        if let pointer = cString as? UnsafeMutablePointer<CUnsignedChar> {
            self = String(cString: pointer)
            return
        }

        if let string = String(fromTuple: cString) {
            self = string
            return
        }

        return nil
    }
}

// https://stackoverflow.com/a/58869882/4488252

struct Tuple<T> {
    let original: T
    private let array: [Mirror.Child]
    init(_ value: T) {
        self.original = value
        array = Array(Mirror(reflecting: original).children)
    }
    func compactMap<V>(_ transform: (Mirror.Child) -> V?) -> [V] { array.compactMap(transform) }

    func toString() -> String? {

        let chars = compactMap { (_, value) -> String? in
            var scalar: Unicode.Scalar!
            switch value {
            case is CUnsignedChar: scalar = .init(value as! CUnsignedChar)
            case is CChar: scalar = .init(UInt8(value as! CChar))
            default: break
            }
            guard let _scalar = scalar else { return nil }
            return String(_scalar)
        }
        if chars.isEmpty && !array.isEmpty { return nil }
        return chars.joined()
    }
}
#ifndef Header_h
#define Header_h

#ifdef __cplusplus
extern "C" {
#endif

char c_str1[] = "Hello world!";
char c_str2[50] = "Hello world!";
char *c_str3 = c_str2;

typedef unsigned char UTF8CHAR;
UTF8CHAR c_str4[] = {72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 0};
UTF8CHAR *c_str5 = c_str4;
UTF8CHAR c_str6[] = {'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\0'};
UTF8CHAR *c_str7 = 0;
UTF8CHAR *c_str8 = "";

#define UI BYTE

#ifdef __cplusplus
}
#endif

#endif /* Header_h */
#include "Header.h"
func test() {
    printInfo(c_str1)
    printInfo(c_str2)
    printInfo(c_str3)
    printInfo(c_str4)
    printInfo(c_str5)
    printInfo(c_str6)
    printInfo(c_str7)
    printInfo(c_str8)

    print(String(fromTuple: c_str1) as Any)
    print(String(fromTuple: c_str2) as Any)
    print(String(cString: c_str3) as Any)
    print(String(fromTuple: c_str4) as Any)
    print(String(cString: c_str5) as Any)
    print(String(fromTuple: c_str6) as Any)
    print(String(fromTuple: c_str7) as Any)
    print(String(cString: c_str8) as Any)
}

var counter = 1;

func printInfo(_ value: Any?) {
    print("name: str_\(counter)")
    counter += 1
    guard let value = value else { return }
    print("type: \(type(of: value))")
    print("value: \(value)")
    print("swift string: \(String(cString: value))")
    print("\n-----------------")
}
name: str_1
type: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
value: (72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 0)
swift string: Optional("Hello world!\0")

-----------------
name: str_2
type: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
value: (72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
swift string: Optional("Hello world!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")

-----------------
name: str_3
type: UnsafeMutablePointer<Int8>
value: 0x000000010e8c5d40
swift string: Optional("Hello world!")

-----------------
name: str_4
type: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
value: (72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 32, 0)
swift string: Optional("Hello world \0")

-----------------
name: str_5
type: UnsafeMutablePointer<UInt8>
value: 0x000000010e8c5d80
swift string: Optional("Hello world ")

-----------------
name: str_6
type: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
value: (72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 0)
swift string: Optional("Hello world!\0")

-----------------
name: str_7
name: str_8
type: UnsafeMutablePointer<UInt8>
value: 0x000000010e8c0ae0
swift string: Optional("")

-----------------
Optional("Hello world!\0")
Optional("Hello world!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
Optional("Hello world!")
Optional("Hello world \0")
Optional("Hello world ")
Optional("Hello world!\0")
Optional("")
Optional("")