Swift sysctl获取整数

4

我正在尝试制作一个应用程序来读取系统信息(在MacOS上),我已经能够像这样读取sysctl字符串:

 func cpu() -> String {
    var size = 0
    sysctlbyname("machdep.cpu.brand_string", nil, &size, nil, 0)
    var machine = [CChar](repeating: 0,  count: Int(size))
    sysctlbyname("machdep.cpu.brand_string", &machine, &size, nil, 0)
    return String(cString: machine)

}

但是当我尝试读取像hw.cpufrequency这样的整数时:

func cpuFreq() -> String {
    var size = 0
    sysctlbyname("hw.cpufrequency", nil, &size, nil, 0)
    var machine = [CChar](repeating: 0,  count: Int(size))
    sysctlbyname("hw.cpufrequency", &machine, &size, nil, 0)
    return String(cString: machine)

}

它完全没有返回任何东西,有什么线索吗?
2个回答

4

你的代码假设返回值是一个字符串,但实际上它是一个整数。如果你查看sysctl(3) 的手册页 [在终端中输入'man 3 sysctl'可以看到它],你会发现"CpuFrequency" 在 C 中返回一个 int64_t,这在 Swift 中对应 Int64。所以你需要将值读入一个 Int64 变量,而不是一个字符串。可以像这样实现:

func cpuFreq() throws -> Int64 {
    var frequency: Int64 = 0
    var size = MemoryLayout<Int64>.size

    if sysctlbyname("hw.cpufrequency", &frequency, &size, nil, 0) != 0 {
        throw POSIXError.Code(rawValue: errno).map { POSIXError($0) } ?? CocoaError(.fileReadUnknown)
    }

    return frequency
}

1
在你的情况下,你正在尝试使用检索字符串值的代码来检索整数值,因此它不会起作用。
基本上,sysctl给你两种类型的值(除了值表),它们是整数和字符串。
这里是我为我的库SwiftCPUDetect编写的一些代码,以检索两者:
//Strings
func getString(_ name: String) -> String?{
    
    var size: size_t = 0
    //gets the string size
    var res = sysctlbyname(name, nil, &size, nil, 0)
    
    if res != 0 {
        //Returns nil if the specified name entry has not been found
        return nil
    }
    //Allocates the appropriate vector (with extra termination just t be sure)
    var ret = [CChar].init(repeating: 0, count: size + 1)
    //retrives value
    res = sysctlbyname(name, &ret, &size, nil, 0)
    
    return res == 0 ? String(cString: ret) : nil
}

//Integers
func getInteger<T: FixedWidthInteger>(_ name: String) -> T?{
    var ret = T()
    
    var size = MemoryLayout.size(ofValue: ret) //gets the size of the provided integer value
    
    let res = sysctlbyname(name, &ret, &size, nil, 0) //fetches the value
    
    return res == 0 ? ret : nil //returns the retrieved integer if the value name entry exists otherwise returns nil
}

以下是一些示例用法(仅适用于 macOS):

///Gets the number of cores of the current CPU
func cores_count() -> UInt?{
    return getInteger("machdep.cpu.core_count")
}
        
///Gets the brand name for the current CPU
func brand_string() -> String?{
    return getString("machdep.cpu.brand_string")
}

另外,sysctl可以使用设置为0或1的整数来处理布尔值,因此您可以使用这个简单的函数检索布尔值:

//Boolean
func getBool(_ name: String) -> Bool?{
    guard let res: Int32 = getInteger(name) else{
        return nil
    }
    
    return res == 1
}

我希望这对你有所帮助,欢迎在你的项目中使用我提到的库,它包含了许多像这样有用的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接