【问题标题】:How can I assign literal integer to enum with raw value that overflows?如何将文字整数分配给原始值溢出的枚举?
【发布时间】:2023-03-18 03:32:01
【问题描述】:

当您打开 IOKit/usb/USB.h 时,您会看到如下常量:

#define err_system(x)    (signed((unsigned(x) & 0x3f) << 26))
#define err_sub(x)       ((x & 0xfff) << 14)

#define sys_iokit         err_system(0x38)
#define sub_iokit_usb     err_sub(1)

#define iokit_usb_err(return)   (IOReturn)(sys_iokit|sub_iokit_usb|return)


//Then all errors are defined like:

#define kIOUSBUnknownPipeErr   iokit_usb_err(0x61)   //0xe0004061
kIOUSBTooManyPipesErr          iokit_usb_err(0x60)   //0xe0004060
.
.   

所以我决定快速尝试一下:

private enum IOUSBError: IOReturn {
    case unknownPipeErr = 0xe0004061
    case tooManyPipesErr = 0xe0004060
    .
    .
}

但它给出了错误:"Integer literal '3758112865' overflows when stored into 'IOReturn' (aka 'Int32')"

对于每一个枚举案例..

知道如何故意允许这样做吗?

【问题讨论】:

  • C 代码采用无符号 32 位数字并将其转换为有符号 32 位数字。这在 C 中有效。在 Swift 中,你得到了溢出。您需要在 Swift 中执行一些技巧以将 32 位无符号值粘贴到 32 位有符号变量(大小写)中。
  • @rmaddy;这适用于常量,但不适用于 Swift 中的枚举 :(
  • 0xe0004061-0x1fffbf9f0xe0004060-0x1fffbfa0 当从无符号转换为有符号时。
  • 使用print(String(Int32(bitPattern: 0xe0004060), radix: 16))进行转换。

标签: swift


【解决方案1】:

据我所知,如果值超出有符号类型的范围,则不能将无符号整数文字分配给具有有符号整数原始类型的枚举。

正如@rmaddy 建议的那样,预先计算等效的有符号值是一种选择。

另一种选择是使用带有静态属性的struct

struct IOUSBErr {

    static let kIOUSBUnknownPipeErr  = IOReturn(bitPattern: 0xe0004061)
    static let kIOUSBTooManyPipesErr = IOReturn(bitPattern: 0xe0004060)
    // ...
}

或用 Swift 函数替换 C 宏(未导入 Swift):

struct IOUSBErr {

    static func err_system(_ x: UInt32) -> IOReturn {
        return IOReturn(bitPattern: (x & 0x3f) << 26)
    }

    static func err_sub(_ x: UInt32) -> IOReturn {
        return IOReturn(bitPattern: (x & 0xfff) << 14)
    }

    static let sys_iokit = err_system(0x38)
    static let sub_iokit_usb = err_sub(1)

    static func iokit_usb_err(_ ret: UInt32) -> IOReturn {
        return sys_iokit|sub_iokit_usb|IOReturn(bitPattern: ret)
    }

    static let kIOUSBUnknownPipeErr  = iokit_usb_err(0x61)
    static let kIOUSBTooManyPipesErr = iokit_usb_err(0x60)

}

(静态属性在第一次访问时初始化一次。)

【讨论】:

  • 我最终创建了枚举 Int64, CaseIterable,循环了所有案例并通过位模式与 Int32 进行比较。这样我就没有改变我所有的代码。但是您使用 Struct 的解决方案很好。
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 2021-10-21
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
相关资源
最近更新 更多