快速读取 char(不是 char *)作为 C 字符串指针
Posted
技术标签:
【中文标题】快速读取 char(不是 char *)作为 C 字符串指针【英文标题】:Swift reading char (not char *) as C string pointer 【发布时间】:2018-03-16 13:10:24 【问题描述】:这周我刚开始使用 Swift,特别是 Swift 4,我正在通过一个桥接头使用 C 库,liblo,它处理通过网络套接字发送/接收 OSC(开放声音控制)格式的消息.
我能够启动一个服务器线程,通过 C 回调->Swift 闭包接收 OSC 消息,并使用 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 的地址并将其提供给有效的 String,但只获取第一个字符:
// 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】:经过一番挖掘,我可以确认 Swift 在我的 64 位系统(即 sizeof(char)
)上将 lo_arg->s
和 lo_arg->S
字符串值截断为 8 个字节。当试图从 来自 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 中,我可以转换为字符串:
let s = String(cString: lo_message_get_string(msg, 0))
// do something with s
【讨论】:
以上是关于快速读取 char(不是 char *)作为 C 字符串指针的主要内容,如果未能解决你的问题,请参考以下文章
将字节数组从 C# 传递到 C++ DLL 作为 char*
从具有指定字节顺序的二进制 unsigned char* 读取 C 中的 double