使用 Swift 中的数组指针和 int 指针调用 C 函数
Calling C function with array pointer and int pointer from Swift
我正在创建一个 C 库和一个包装器以便于在 Swift 中使用。 C函数有两个参数,一个数组指针和一个int指针:
int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
int err = 0;
size_t length = 0;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
// Call sysctl with a NULL buffer to get proper length
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
//if (err) return [-1];
// Get the actual process list
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, proc_list, &length, NULL, 0);
//if (err) return [-1];
*count = length / sizeof(struct kinfo_proc);
for (int i = 0; i < *count; i++) {
struct kinfo_proc proc = proc_list[i];
proc = proc;
}
return 1;
}
我从我的 Swift 包装器中调用该函数:
var data: [Process] = []
override func viewDidLoad() {
super.viewDidLoad()
let proc_list: UnsafeMutablePointer<kinfo_proc> = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: 500)
var count: size_t = 0
let result = crgetproclist(proc_list, &count)
var foobar: [Process] = []
if (result == 1) {
for i in 1..<count {
var proc: kinfo_proc = proc_list[i]
var process = Process(proc: proc)
foobar.append(process) // <---- works
self.data.append(process) // <---- EXC_BAD_ACCESS ????
}
self.data.sort(by: {
(a: Process, b: Process) -> Bool in
return a.name.lowercased() < b.name.lowercased()
})
self.myTable.reloadData()
}
}
class Process: NSObject {
var _proc: kinfo_proc
var pid: pid_t
var name: String
var icon: NSImage?
var isAlive: Bool = false
var uid: uid_t = 0
init(proc: kinfo_proc) {
self._proc = proc
self.pid = proc.kp_proc.p_pid
self.name = String(cString: crgetprocname(pid))
self.uid = crgetuid(pid)
super.init()
}
}
问题
如何正确创建 UnsafeMutablePointer 并将其传递给 C 函数?我硬编码容量:500 可以工作,但是如何在没有硬编码容量的情况下正确执行?
当我尝试将它附加到我的 class 变量数组数据时,它遇到了 EXC_BAD_ACCESS,但是当我将它附加到相同类型的 foobar 时,它起作用了.为什么?如何在没有内存错误的情况下将其分配给 class 变量?
我只能回答你问题的第一部分:为了确定进程列表的必要分配计数,你必须允许使用 NULL 参数调用 crgetproclist()
(与 sysctl()
可以使用 NULL 参数调用 oldp
以获得所需的缓冲区大小):
int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
int err = 0;
size_t length;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
if (proc_list == NULL) {
// Call sysctl with a NULL buffer to get proper length
length = 0;
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), NULL, &length, NULL, 0);
} else {
// Get the actual process list
length = *count * sizeof(struct kinfo_proc);
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), proc_list, &length, NULL, 0);
}
if (err) return -1;
*count = length / sizeof(struct kinfo_proc);
return 1;
}
现在您可以从 Swift 调用该函数两次:首先确定分配计数,然后再次检索进程列表:
var count: size_t = 0
crgetproclist(nil, &count)
let procList = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)
if crgetproclist(procList, &count) == 1 {
for i in 0..<count {
let proc = procList[i]
// ...
}
}
procList.deallocate()
另请注意,您可以在纯 Swift:
中轻松实现该功能
func getProcessList() -> [kinfo_proc]? {
var name : [Int32] = [ CTL_KERN, KERN_PROC, KERN_PROC_ALL ]
var length = size_t()
sysctl(&name, UInt32(name.count), nil, &length, nil, 0)
let count = length / MemoryLayout<kinfo_proc>.size
var procList = Array(repeating: kinfo_proc(), count: count)
let result = sysctl(&name, UInt32(name.count), &procList, &length, nil, 0)
guard result == 0 else { return nil } // Some error ...
return Array(procList.prefix(length / MemoryLayout<kinfo_proc>.size))
}
我正在创建一个 C 库和一个包装器以便于在 Swift 中使用。 C函数有两个参数,一个数组指针和一个int指针:
int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
int err = 0;
size_t length = 0;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
// Call sysctl with a NULL buffer to get proper length
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
//if (err) return [-1];
// Get the actual process list
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, proc_list, &length, NULL, 0);
//if (err) return [-1];
*count = length / sizeof(struct kinfo_proc);
for (int i = 0; i < *count; i++) {
struct kinfo_proc proc = proc_list[i];
proc = proc;
}
return 1;
}
我从我的 Swift 包装器中调用该函数:
var data: [Process] = []
override func viewDidLoad() {
super.viewDidLoad()
let proc_list: UnsafeMutablePointer<kinfo_proc> = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: 500)
var count: size_t = 0
let result = crgetproclist(proc_list, &count)
var foobar: [Process] = []
if (result == 1) {
for i in 1..<count {
var proc: kinfo_proc = proc_list[i]
var process = Process(proc: proc)
foobar.append(process) // <---- works
self.data.append(process) // <---- EXC_BAD_ACCESS ????
}
self.data.sort(by: {
(a: Process, b: Process) -> Bool in
return a.name.lowercased() < b.name.lowercased()
})
self.myTable.reloadData()
}
}
class Process: NSObject {
var _proc: kinfo_proc
var pid: pid_t
var name: String
var icon: NSImage?
var isAlive: Bool = false
var uid: uid_t = 0
init(proc: kinfo_proc) {
self._proc = proc
self.pid = proc.kp_proc.p_pid
self.name = String(cString: crgetprocname(pid))
self.uid = crgetuid(pid)
super.init()
}
}
问题
如何正确创建 UnsafeMutablePointer 并将其传递给 C 函数?我硬编码容量:500 可以工作,但是如何在没有硬编码容量的情况下正确执行?
当我尝试将它附加到我的 class 变量数组数据时,它遇到了 EXC_BAD_ACCESS,但是当我将它附加到相同类型的 foobar 时,它起作用了.为什么?如何在没有内存错误的情况下将其分配给 class 变量?
我只能回答你问题的第一部分:为了确定进程列表的必要分配计数,你必须允许使用 NULL 参数调用 crgetproclist()
(与 sysctl()
可以使用 NULL 参数调用 oldp
以获得所需的缓冲区大小):
int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
int err = 0;
size_t length;
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
if (proc_list == NULL) {
// Call sysctl with a NULL buffer to get proper length
length = 0;
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), NULL, &length, NULL, 0);
} else {
// Get the actual process list
length = *count * sizeof(struct kinfo_proc);
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), proc_list, &length, NULL, 0);
}
if (err) return -1;
*count = length / sizeof(struct kinfo_proc);
return 1;
}
现在您可以从 Swift 调用该函数两次:首先确定分配计数,然后再次检索进程列表:
var count: size_t = 0
crgetproclist(nil, &count)
let procList = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)
if crgetproclist(procList, &count) == 1 {
for i in 0..<count {
let proc = procList[i]
// ...
}
}
procList.deallocate()
另请注意,您可以在纯 Swift:
中轻松实现该功能func getProcessList() -> [kinfo_proc]? {
var name : [Int32] = [ CTL_KERN, KERN_PROC, KERN_PROC_ALL ]
var length = size_t()
sysctl(&name, UInt32(name.count), nil, &length, nil, 0)
let count = length / MemoryLayout<kinfo_proc>.size
var procList = Array(repeating: kinfo_proc(), count: count)
let result = sysctl(&name, UInt32(name.count), &procList, &length, nil, 0)
guard result == 0 else { return nil } // Some error ...
return Array(procList.prefix(length / MemoryLayout<kinfo_proc>.size))
}