Swift读取char(不是char *)作为C字符串指针

时间:2018-03-16 13:10:25

标签: swift osc

本周我刚开始使用Swift,特别是Swift 4,我通过桥接头liblo使用C库,它处理发送/接收OSC(开放声音控制)格式的消息通过网络套接字。

我能够启动服务器线程,通过C回调接收OSC消息 - > Swift闭包,并使用Swift读取数值参数值就好了。但是,我在阅读字符串值时遇到了麻烦。

liblo消息参数类型lo_arg is a C typedef for a union和字符串参数类型被声明为简单字符,它们作为Int8映射到Swift。

在C中,您可以从回调的&argv[i]->s数组中通过lo_arg **argv获取字符串。在使用liblo的Obj-C项目中,我使用:

// get string value of first argument
lo_arg arg = argv[0];
NSString *s = [NSString stringWithUTF8String:&arg->s];
// do something with s

在Swift中,我尝试获取Int8的地址并将其提供给有效的字符串,但只抓取第一个字符:

// get string value of first argument
if var arg : lo_arg = argv?.pointee![0] {
    withUnsafePointer(to: &arg.s) {
        let s = String(cString: $0)
        // so something with s
    }
}

我做错了吗?我认为这些是等价的,但是将$0传递给strlen() ala print("strlen: \(strlen($0)")只会打印长度为" 1"。我已经验证了多字符字符串确实是使用非Swift测试程序发送的。我现在想知道Swift是否以某种方式假设字符串是单个字符而不是C字符串头地址和/或我需要进一步指针转换。

1 个答案:

答案 0 :(得分:0)

经过一番挖掘,我可以确认Swift截断了lo_arg->s&我的64位系统上的lo_arg->S字符串值为8个字节,即sizeof(char)。当尝试从来自Swift 的lo_arg中读取字符串时会发生这种情况。在C 中读取相同的值工作正常,因此Swift似乎保留/仅允许从单个字符的空间读取。将lo_arg从Swift转发到C并通过printf()打印字符串也会显示最多8个字符的截断字符串。

快速解决方法是避免从Swift生成的lo_arg中读取字符串,从C中的原始lo_message中获取lo_arg,然后转换char"指针"一个const char * Swift将理解为一个可变长度的字符串。以下是我添加到桥接标题中的一些工作实用程序函数:

/// return an lo_message argv[i]->s in a format Swift can understand as a String
const char* lo_message_get_string(lo_message message, int at) {
    return (const char *)&lo_message_get_argv(message)[at]->s;
}

/// return an lo_message argv[i]->S in a format Swift can understand as a String
const char* lo_message_get_symbol(lo_message message, int at) {
    return (const char *)&lo_message_get_argv(message)[at]->S;
}

在Swift中,我可以转换为String:

let s = String(cString: lo_message_get_string(msg, 0))
// do something with s