简体   繁体   English

Swift 3 - 如何将 Int32 的内存转换为四个字符

[英]Swift 3 - How to convert memory of Int32 as four characters

I want to convert an Int32 to a string consisting of four C-style, 1-byte wide characters (probably closely related to this but in Swift 3 ).我想将Int32转换为由四个 C 样式的 1 字节宽字符组成的字符串(可能与密切相关,但在Swift 3 中)。

The use for this is that many API functions of Core Audio return an OSStatus (really an Int32 ), which can often be interpreted as string consisting of four C-style characters.这样做的用途是 Core Audio 的许多 API 函数返回一个OSStatus (实际上是一个Int32 ),通常可以将其解释为由四个 C 样式字符组成的字符串。

fun interpretAsString(possibleMsg: Int32) -> String {
  // Blackbox
}

Actually a "four character code" is usually an unsigned 32-bit value:实际上,“四字符代码”通常是一个无符号的32 位值:

public typealias FourCharCode = UInt32
public typealias OSType = FourCharCode

The four bytes (from the MSB to the LSB) each define one character.四个字节(从 MSB 到 LSB)每个定义一个字符。 Here is a simple Swift 3 function to convert the integer to a string, inspired by the various C/Objective-C/Swift 1+2 solutions in iOS/C: Convert "integer" into four character string :这是一个简单的 Swift 3 函数将整数转换为字符串,其灵感来自iOS/C 中的各种 C/Objective-C/Swift 1+2 解决方案:将“整数”转换为四个字符串

func fourCCToString(_ value: FourCharCode) -> String {
    let utf16 = [
        UInt16((value >> 24) & 0xFF),
        UInt16((value >> 16) & 0xFF),
        UInt16((value >> 8) & 0xFF),
        UInt16((value & 0xFF)) ]
    return String(utf16CodeUnits: utf16, count: 4)
}

Example:例子:

print(fourCCToString(0x48454C4F)) // HELO

I have chosen an array with the UTF-16 code points as intermediate storage because that can directly be used to create a string.我选择了一个带有 UTF-16 代码点的数组作为中间存储,因为它可以直接用于创建字符串。

If you really need it for a signed 32-bit integer then you can call如果你真的需要一个有符号的32 位整数,那么你可以调用

fourCCToString(FourCharCode(bitPattern: i32value)

or define a similar function taking an Int32 parameter.或者定义一个采用Int32参数的类似函数。

As Tim Vermeulen suggested below, the UTF-16 array can also be created with map :正如 Tim Vermeulen 在下面建议的那样,UTF-16 数组也可以使用map创建:

let utf16 = stride(from: 24, through: 0, by: -8).map {
    UInt16((value >> $0) & 0xFF)
}

or或者

let utf16 = [24, 16, 8, 0].map { UInt16((value >> $0) & 0xFF) }

Unless the function is performance critical for your application, pick what you feel most familiar with (otherwise measure and compare).除非该功能对您的应用程序性能至关重要,否则请选择您最熟悉的功能(否则进行测量和比较)。

I don't test this code but try this:我不测试这段代码,但试试这个:

func interpretAsString(possibleMsg: Int32) -> String {
    var result = String()
    result.append(Character(UnicodeScalar(UInt32(possibleMsg>>24))!))
    result.append(Character(UnicodeScalar(UInt32((possibleMsg>>16) & UInt32(0xFF)))!))
    result.append(Character(UnicodeScalar(UInt32((possibleMsg>>8) & UInt32(0xFF)))!))
    result.append(Character(UnicodeScalar(UInt32((possibleMsg) & UInt32(0xFF)))!))
    return result
}

This may be an old question, but since it was asking in the context of Core Audio, I just wanted to share a variant I was playing with.这可能是一个老问题,但由于它是在 Core Audio 的上下文中提出的,我只想分享我正在使用的一个变体。

For Core Audio, where some (but not all?) OSStatus / Int32 values are defined using four characters, some code from Apple's old Core Audio Utility Classes can provide inspiration (very similar to the linked question )对于 Core Audio,其中一些(但不是全部?) OSStatus / Int32值是使用四个字符定义的,来自 Apple 旧 Core Audio Utility Classes 的一些代码可以提供灵感(非常类似于链接的问题

From CAXException.h :CAXException.h

class CAX4CCStringNoQuote {
public:
    CAX4CCStringNoQuote(OSStatus error) {
        // see if it appears to be a 4-char-code
        UInt32 beErr = CFSwapInt32HostToBig(error);
        char *str = mStr;
        memcpy(str, &beErr, 4);
        if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
            str[4] = '\0';
        } else if (error > -200000 && error < 200000)
            // no, format it as an integer
            snprintf(str, sizeof(mStr), "%d", (int)error);
        else
            snprintf(str, sizeof(mStr), "0x%x", (int)error);
    }
    const char *get() const { return mStr; }
    operator const char *() const { return mStr; }
private:
    char mStr[16];
};

In Swift 5, one rough translation (without the hex representation for large values) might be:在 Swift 5 中,一种粗略的翻译(没有大值的十六进制表示)可能是:

    private func osStatusToString(_ value: OSStatus) -> String {
        let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })

        // If all bytes are printable characters, we treat it like characters of a string
        if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
            return String(data: data, encoding: .ascii)!
        } else {
            return String(value)
        }
    }

Note that the Data initializer is making a copy of the bytes, though it may be possible to avoid that if desired.请注意, Data初始值设定项正在制作字节的副本,但如果需要,可以避免这种情况。

Of course, with Core Audio we encounter four character codes with both Int32 and UInt32 types.当然,在 Core Audio 中,我们遇到Int32UInt32类型的四个字符代码。 I haven't done generics with Swift before, but one way to handle them in a single function could be:我以前没有用 Swift 做过泛型,但在单个函数中处理它们的一种方法可能是:

    private func stringifyErrorCode<T: FixedWidthInteger>(_ value: T) -> String {
        let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })

        // If all bytes are printable characters, we treat it like characters of a string
        if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
            return String(data: data, encoding: .ascii)!
        } else {
            return String(value, radix: 10)
        }
    }

This may not be suitable for general purpose handling of four character codes (I've seen other answers that support characters in the MacOS Roman encoding versus ASCII in the example above. There's likely some history there I'm not aware of), but may be reasonable for Core Audio status/selector codes.这可能不适用于四个字符代码的通用处理(我在上面的示例中看到其他支持 MacOS 罗马编码与 ASCII 字符的答案。可能有一些我不知道的历史),但可能对 Core Audio 状态/选择器代码合理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM