小编典典

MACH_TASK_BASIC_INFO的Swift指针问题

swift

我正在尝试将答案转换为Swift并失败。似乎我正在传递一个UnsafeMutablePointer<mach_msg_type_number_t>应该何时传递一个,inout mach_msg_type_number_t而我似乎无法解决我的问题。据我了解的Swift指针文档(不多),这些应该可以互换。

下面的更多信息。

这是目标C:

struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);

这是我所掌握的Swift语言(很多行可以简化类型检查)

let name: task_name_t = mach_task_self_
let flavor: task_flavor_t = task_flavor_t(MACH_TASK_BASIC_INFO)
var info: mach_task_basic_info
var size: mach_msg_type_number_t = UnsignedFixed(sizeof(mach_task_basic_info_t))
let kerr = task_info(name, flavor, info as task_info_t, &size)

task_info签名是:

func task_info(target_task: task_name_t, flavor: task_flavor_t, task_info_out: task_info_t, task_info_outCnt: UnsafeMutablePointer<mach_msg_type_number_t>) -> kern_return_t

最后一行的错误是:

Cannot convert the expression's type '(@!lvalue task_name_t, task_flavor_t, task_info_t, inout mach_msg_type_number_t)' to type 'kern_return_t'

阅读 402

收藏
2020-07-07

共1个答案

小编典典

与C函数进行交互时,您不能依靠编译器的错误消息-逐个参数地将其分解,然后单击命令直至知道要使用的内容。首先,您遇到的类型是:

  • task_name_tUInt32
  • task_flavor_tUInt32
  • task_info_tUnsafeMutablePointer<Int32>
  • UnsafeMutablePointer<mach_msg_type_number_t>UnsafeMutablePointer<UInt32>
  • kern_return_t -- Int32

这里有一个棘手的Swift位以及代码中的一个错误,阻碍了您的发展。首先,task_info_out参数必须为UnsafeMutablePointer<UInt32>,但实际上需要指向的实例mach_task_basic_info。我们可以通过在调用时创建一个UnsafeMutablePointer<mach_task_basic_info>并将其包装在
另一个 包装中来解决此问题UnsafeMutablePointer-编译器将使用类型推断来知道我们希望将包装指针子类型化为UInt32

其次,您在
应调用时正在调用sizeof(mach_task_basic_info_t)(指向的指针mach_task_basic_infosizeinfo(mach_task_basic_info),因此字节数最终太少而无法容纳数据结构。

在进一步的研究中,这变得更加复杂。原始代码不正确,size应将其初始化为constant
MACH_TASK_BASIC_INFO_COUNT。不幸的是,这是一个宏,而不是简单的常量:

#define MACH_TASK_BASIC_INFO_COUNT (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))

Swift不会导入这些,因此我们需要自己重新定义。这是所有这些的工作代码:

// constant
let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))

// prepare parameters
let name   = mach_task_self_
let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
var size   = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)

// allocate pointer to mach_task_basic_info
var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)

// call task_info - note extra UnsafeMutablePointer(...) call
let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)

// get mach_task_basic_info struct out of pointer
let info = infoPointer.move()

// deallocate pointer
infoPointer.dealloc(1)

// check return value for success / failure
if kerr == KERN_SUCCESS {
    println("Memory in use (in bytes): \(info.resident_size)")
} else {
    let errorString = String(CString: mach_error_string(kerr), encoding: NSASCIIStringEncoding)
    println(errorString ?? "Error: couldn't parse error string")
}
2020-07-07