从 Swift 调用带有数组指针和 int 指针的 C 函数

Posted

技术标签:

【中文标题】从 Swift 调用带有数组指针和 int 指针的 C 函数【英文标题】:Calling C function with array pointer and int pointer from Swift 【发布时间】:2020-07-08 17:25:20 【问题描述】:

我正在创建一个 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 哪个有效,但没有硬编码容量如何正确执行?

    当我尝试将它附加到我的类变量数组数据时,它会运行到 EXC_BAD_ACCESS,但是当我将它附加到与它相同类型的 foobar 时。为什么?如何将其分配给类变量而不会出现内存错误?

【问题讨论】:

【参考方案1】:

我只能回答您问题的第一部分:为了确定进程列表的必要分配计数,您必须允许使用 NULL 参数调用 crgetproclist()(与 sysctl() 相同的方式可以使用 oldp 的 NULL 参数调用以获取所需的缓冲区大小):

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))

【讨论】:

谢谢你,也感谢你的纯 Swift 实现。帮助我更习惯 Swift 中低级 C 数据类型的使用。

以上是关于从 Swift 调用带有数组指针和 int 指针的 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

带有空指针的 2D 指针数组 c++

多维数组和多维指针

c语言如何给指针参数赋值为null?

c ++对象数组+带有引用和指针的参数

第34课 多维数组和多维指针

模拟qsort实现冒泡排序