在 Swift 中获取 ioctl 数字

Getting ioctl numbers in Swift

我在这里想要实现的是获取用于弹出磁盘的 ioctl 编号,我已经在我的桥接 Header:

#define DKIOCEJECT  _IO('d', 21)

NSUInteger IOEJECT = DKIOCEJECT;

...这确实适用于创建 ioctl 请求,我想做的只是 Swift 而不是必须使用桥接 Header

在 C 中,我通常会放这样的东西来得到一个 ioctl 数字:

#define DKIOCEJECT _IO('d', 21)

上面通常会 return 一个 ioctl 数字,我怎样才能做类似的事情但是在 Swift?


以下是所有预处理器宏:

#define _IO(g, n)        _IOC(IOC_VOID, (g), (n), 0)

#define _IOC(inout, group, num, len) \  (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))

#define IOCPARM_MASK    0x1fff          /* parameter length, at most 13 bits */

define IOC_VOID        (__uint32_t)0x20000000

鉴于 _IO 宏解析为单个整数常量,我们可以按照预处理器的逻辑重新实现它:

#define DKIOCEJECT                     _IO('d', 21)
#define _IO(g, n)                      _IOC(IOC_VOID, (g), (n), 0)
#define _IOC(inout, group, num, len)   (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define IOC_VOID                       (unsigned long)0x20000000
#define IOCPARM_MASK                   0x1fff

因此....

DKIOCEJECT  == _IO(g: 'd', n: 21)
            == _IOC(IOC_VOID, ('d'), (21), 0)
            == (IOC_VOID | ((0 & IOCPARM_MASK) << 16) | (('d') << 8) | (21))
            == ( 0x20000000 | (0 << 16) | (('d') << 8) | (21) )
            == ( 0x20000000 | 0         | (0x64 << 8)  | 21   )
            == ( 0x20000000             | 0x6400       | 0x15 )
            == 0x20006415

// For reference:
'd'         == 0x64 // asciitable.com
21          == 0x15

在Swift中作为文字常量:

enum MyIoctrlNumbers {
    static let DKIOCEJECT: UInt = 0x20006415
}

Swift 不支持 C++ 风格的 constexpr 表达式,但是如果您对运行时生成的 static 值没问题,那么试试这个:

import Foundation

func getIoctrlNumber( group: Character, n: UInt ) -> UInt {

    let IOC_VOID: UInt = 0x20000000;
    let g       : UInt = UInt( UInt( group.asciiValue! ) << 8 );

    return IOC_VOID | g | n;
}

let asInt = getIoctrlNumber( group: "d", n: 21 );
let asDec = String( asInt, radix: 10 );
let asHex = String( asInt, radix: 16 );
print( "DKIOCEJECT == "   + asDec );
print( "DKIOCEJECT == 0x" + asHex );

给我这个输出:

Swift version 5.5.1 (swift-5.5.1-RELEASE)                                                   02:11:39 4s
Target: x86_64-unknown-linux-gnu

DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415

显然 Swift 确实 让你用运行时初始化 static 值填充 enum 的值(不仅仅是 consts/literals!), 所以你可以这样:

enum MyIoctrlNumbers {

    static let DKIOCEJECT: UInt = getIoctrlNumber( group: "d", n: 21 );
    static let ANOTHER   : Uint = getIoctrlNumber( group: "e", n: 22 );
}

这很好用:

print( "DKIOCEJECT == "   + String( MyIoctrlNumbers.DKIOCEJECT, radix: 10 ));
print( "DKIOCEJECT == 0x" + String( MyIoctrlNumbers.DKIOCEJECT, radix: 16 ) );

给我这个输出:

Swift version 5.5.1 (swift-5.5.1-RELEASE)                                                   02:13:31 6s
Target: x86_64-unknown-linux-gnu


DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415