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

3
我想把一个 Int32 转换成由四个C风格、1字节宽的字符组成的字符串(可能与这个非常相似,但用于 Swift 3)。
这样做的原因是,Core Audio 的许多 API 函数返回一个 OSStatus(实际上是一个 Int32),通常可以被解释为由四个 C 风格字符组成的字符串。
fun interpretAsString(possibleMsg: Int32) -> String {
  // Blackbox
}

可能是重复的问题:如何在Swift中将Int16转换为两个UInt8字节 - BallpointBen
你尝试过使用NSFileTypeForHFSTypeCode吗?尽管它的名称如此,但它可以将任何来自OSType的4个字符代码转换为String - Code Different
@CodeDifferent:这在iOS上不可用。 - Martin R
请参考以下链接:https://dev59.com/9V0Z5IYBdhLWcg3wiw7n - pkamb
3个回答

4
实际上,“四字符代码”通常是一个无符号32位值:
public typealias FourCharCode = UInt32
public typealias OSType = FourCharCode

这四个字节(从最高位到最低位)每个都定义了一个字符。以下是一个简单的Swift 3函数,用于将整数转换为字符串,灵感来自iOS/C: Convert "integer" into four character string中的各种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)
}

例子:

print(fourCCToString(0x48454C4F)) // HELO

我选择使用UTF-16码点数组作为中间存储,因为可以直接用于创建字符串。
如果您真的需要一个带符号的32位整数,则可以调用。
fourCCToString(FourCharCode(bitPattern: i32value)

或者定义一个接受Int32参数的类似函数。

正如Tim Vermeulen在下面提到的那样,UTF-16数组也可以使用map创建:

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

或者

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

除非这个函数对你的应用程序的性能至关重要,否则选择你最熟悉的(否则进行测量和比较)。


我通常使用UInt16(UInt8.max)代替有些神奇的0xFF,虽然我猜这是一个经验问题。我还建议使用map来创建chars数组,在你最后的编辑中可以节省一些时间 :) - Tim Vermeulen
@TimVermeulen:感谢您的反馈。我这样写是因为它易于理解,并且我假设它可以让编译器更好地优化代码(没有调用回调的方法)。 - Martin R
我认为编译器可以优化掉map,但是你需要查看生成的汇编代码。对于stride我不太有信心,但如果这是个问题,你可以随时将其替换为[24, 16, 8, 0] - Tim Vermeulen

1
我没有测试这段代码,但请尝试以下代码:

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
}

0
这可能是一个老问题,但由于它是在 Core Audio 的上下文中提出的,我只想分享一个我正在尝试的变体。
对于 Core Audio,在某些(但不是全部?)OSStatus/Int32 值使用四个字符定义的情况下,可以从苹果旧的 Core Audio 实用程序类的一些代码中获得灵感(与链接问题非常相似)。
来自 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];
};

在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)
        }
    }

请注意,Data初始化器正在复制字节,但如果需要,可以避免这种情况。
当然,对于Core Audio,我们会遇到使用Int32UInt32类型的四字符代码。我以前没有用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)
        }
    }

这可能不适用于一般处理四个字符代码(我看到其他答案支持MacOS Roman编码中的字符,而上面的示例则是ASCII。那里可能有一些历史,我不知道),但对于Core Audio状态/选择器代码可能是合理的。


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