c - Swift:将已分配的字符数组转换为字符指针
问题描述
我正在尝试将现有的 C 库连接到 iOS 上的 Swift 5.0.1 代码。C 头文件具有以下定义:
char hostname[SFL_MAX_HOSTNAME_CHARS+1];
char os_release[SFL_MAX_OSRELEASE_CHARS+1];
int readHidCounters(HSP *sp, SFLHost_hid_counters *hid, char *hbuf, int hbufLen, char *rbuf, int rbufLen);
typedef struct _HSP {
[Many other elements omitted for brevity]
char hostname[SFL_MAX_HOSTNAME_CHARS+1];
char os_release[SFL_MAX_OSRELEASE_CHARS+1];
} HSP;
readHidCounters
有一个像这样的实现(为简洁而编辑):
int readHidCounters(HSP *sp, SFLHost_hid_counters *hid, char *hbuf, int hbufLen, char *rbuf, int rbufLen) {
int gotData = NO;
size_t len = hbufLen;
if(sysctlbyname("kern.hostname", hbuf, &len, NULL, 0) != 0) {
myLog(LOG_ERR, "sysctl(<kern.hostname>) failed : %s", strerror(errno));
}
else {
gotData = YES;
hid->hostname.str = hbuf;
hid->hostname.len = strlen(hbuf);
}
// UUID
memcpy(hid->uuid, sp->uuid, 16);
[...]
}
我创建了一个 HSP 结构并尝试readHidCounters
像这样在 Swift中调用
var sp = HSP()
[...]
readHidCounters(&sp,
&hidElem.counterBlock.host_hid,
&sp.hostname, // This is the error line
SFL_MAX_HOSTNAME_CHARS,
&sp.os_release,
SFL_MAX_OSRELEASE_CHARS)
我试图&sp.hostname
在编译器错误中传递结果Cannot convert value of type '(Int8, Int8, Int8, [...], Int8)' to expected argument type 'Int8'
。问题是主机名是 Int8 的元组,我似乎无法将其正确转换为char *
. 我尝试了 的各种化身UnsafeMutablePointer
,withUnsafeMutablePointer
但看不到如何hostname
正确识别。任何建议都非常感谢!
[解决了]
MartinR 几乎用他的建议解决了这个问题,但它确实有一个编译器错误:Overlapping accesses to 'sp.hostname', but modification requires exclusive access; consider copying to a local variable
. 编译的更新代码是
var myHostName = sp.hostname
var myOsRelease = sp.os_release
let _ = withUnsafeMutablePointer(to: &myHostName) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout.size(ofValue: sp.hostname)) {
hostNamePtr in
withUnsafeMutablePointer(to: &myOsRelease) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout.size(ofValue: sp.os_release)) {
osReleasePtr in
readHidCounters(&sp,
&hidElem.counterBlock.host_hid,
hostNamePtr, SFL_MAX_HOSTNAME_CHARS,
osReleasePtr, SFL_MAX_OSRELEASE_CHARS)
}
}
}
}
解决方案
“问题”是 C 数组作为元组导入到 Swift 中,没有简单的方法可以将元组视为 Swift 数组,或者获取指向元素存储的指针(因为元组可能是不均匀的)。
与将 C 字符数组转换为字符串类似,可以使用 Swift 保留从 C 导入的结构的内存布局这一事实,并且通过一些指针杂耍和重新绑定,您将得到
let result = withUnsafeMutablePointer(to: &sp.hostname) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout.size(ofValue: sp.hostname)) {
hostNamePtr in
withUnsafeMutablePointer(to: &sp.os_release) {
$0.withMemoryRebound(to: Int8.self, capacity: MemoryLayout.size(ofValue: sp.os_release)) {
osReleasePtr in
readHidCounters(&sp,
&hidElem.counterBlock.host_hid,
hostNamePtr, SFL_MAX_HOSTNAME_CHARS,
osReleasePtr, SFL_MAX_OSRELEASE_CHARS)
}
}
}
}
另一个“技巧”是定义将数组地址作为指针返回的 C 辅助函数,并使用
使这些辅助函数可用作 Swift 计算属性的功能。在桥接头文件中,您必须添加
__attribute__((swift_name("getter:HSP.hostNamePtr(self:)")))
static inline char * _Nonnull hostNamePtr(HSP * _Nonnull hsp)
{
return hsp->hostname;
}
__attribute__((swift_name("getter:HSP.osReleasePtr(self:)")))
static inline char * _Nonnull osReleasePtr(HSP * _Nonnull hsp)
{
return hsp->os_release;
}
然后你可以从 Swift 中轻松使用这些:
var sp = HSP()
let result = readHidCounters(&sp,
&hidElem.counterBlock.host_hid,
sp.hostNamePtr, SFL_MAX_HOSTNAME_CHARS,
sp.osReleasePtr, SFL_MAX_OSRELEASE_CHARS)
推荐阅读
- haskell - 如何修复缩进?Haskell:输入“|”时解析错误
- python - 无法使用 python 3.7 重新安装 spacy
- xcode - Xcode 中的默认 iCloud 容器发生了什么变化
- oracle - Oracle查询按连续值分组并获取开始日期和结束日期
- android - Android WorkManager SQLiteException: no such table: worktag (code 1 SQLITE_ERROR): ,编译时:
- go - 我有一个带有 4 个物理内核的单处理器,每个内核有 2 个线程。但为什么 runtime.NumCPU() 返回 4 而不是 8?
- python - 将嵌套的 JSON 文件展平为 Pandas DF
- image - 如何在 Safari 浏览器中添加 webp 支持
- jquery - 引导框对话框窗口不能垂直滚动?
- c - 在C中存储未知迭代次数的while循环的结果