iOS / C:将“整数”转换为四个字符串

时间:2013-01-08 19:18:41

标签: ios c

许多与音频会话编程相关的常量实际上是四个字符的字符串(Audio Session Services Reference)。这同样适用于AudioSessionGetProperty等函数返回的OSStatus code

问题在于,当我尝试打开这些东西时,它们看起来像1919902568.我可以将其插入计算器并打开ASCII输出,它会告诉我“roch”,但必须有一个以编程方式执行此操作。

我在我的一个C函数中使用以下块进行了有限的成功:

char str[20];
// see if it appears to be a four-character code
*(UInt32 *) (str + 1) = CFSwapInt32HostToBig(error);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
    str[0] = str[5] = '\'';
    str[6] = '\0';
} else {
    // no, format as integer
    sprintf(str, "%d", (int)error);
}

我想要做的是将此功能从其当前功能中抽象出来,以便在其他地方使用它。我试着做了

char * fourCharCode(UInt32 code) {
    // block
}
void someOtherFunction(UInt32 foo){
    printf("%s\n",fourCharCode(foo));
}

但是这给了我“à*€/3íT:ê*€/ +€/”,而不是“roch”。我的C fu不是很强,但我的预感是上面的代码试图将内存地址解释为字符串。或者可能存在编码问题?有什么想法吗?

14 个答案:

答案 0 :(得分:16)

您所谈论的类型是FourCharCode,在CFBase.h中定义。它等同于OSType。在OSTypeNSString之间进行转换的最简单方法是使用NSFileTypeForHFSTypeCode()NSHFSTypeCodeFromFileType()。遗憾的是,这些功能在iOS上不可用。

对于iOS和Cocoa可移植代码,我喜欢Joachim Bengtsson's中的NCCommon.h FourCC2Str()(加上一点点清理以便于使用):

#include <TargetConditionals.h>
#if TARGET_RT_BIG_ENDIAN
#   define FourCC2Str(fourcc) (const char[]){*((char*)&fourcc), *(((char*)&fourcc)+1), *(((char*)&fourcc)+2), *(((char*)&fourcc)+3),0}
#else
#   define FourCC2Str(fourcc) (const char[]){*(((char*)&fourcc)+3), *(((char*)&fourcc)+2), *(((char*)&fourcc)+1), *(((char*)&fourcc)+0),0}
#endif

FourCharCode code = 'APPL';
NSLog(@"%s", FourCC2Str(code));
NSLog(@"%@", @(FourCC2Str(code));

您当然可以将@()放入宏中,以便更轻松地使用。

答案 1 :(得分:5)

在Swift中你会使用这个函数:

func str4 (n: Int) -> String
{
    var s: String = ""
    var i: Int = n

    for var j: Int = 0; j < 4; ++j
    {
        s = String(UnicodeScalar(i & 255)) + s
        i = i / 256
    }

    return (s)
}

这个功能将在三分之一的时间内完成同样的操作:

func str4 (n: Int) -> String
{
    var s: String = String (UnicodeScalar((n >> 24) & 255))
    s.append(UnicodeScalar((n >> 16) & 255))
    s.append(UnicodeScalar((n >> 8) & 255))
    s.append(UnicodeScalar(n & 255))
    return (s)
}

相反的方式是:

func val4 (s: String) -> Int
{
    var n: Int = 0
    var r: String = ""
    if (countElements(s) > 4)
    {
        r = s.substringToIndex(advance(s.startIndex, 4))
    }
    else
    {
        r = s + "    "
        r = r.substringToIndex(advance(r.startIndex, 4))
    }
    for UniCodeChar in r.unicodeScalars
    {
        n = (n << 8) + (Int(UniCodeChar.value) & 255)
    }

    return (n)
}

答案 2 :(得分:4)

整数= 4个字节= 4个字符。因此,要从整数转换为char *,您只需编写:

char st[5] = {0};
st[0] = yourInt & 0xff;
st[1] = (yourInt >> 8) & 0xff;
st[2] = (yourInt >> 16) & 0xff;
st[3] = (yourInt >> 24) & 0xff;

将其转换回来:

yourInt = st[0] | (st[1] << 8) | (st[2] << 16) | (st[3] << 24);

答案 3 :(得分:3)

char str[5];
str[4] = '\0';
long *code = (long *)str;
*code = 1919902568;
printf("%s\n", str);

答案 4 :(得分:3)

这是我在测试目标中使用的辅助功能:

迅速5:

extension FourCharCode {
    private static let bytesSize = MemoryLayout<Self>.size
    var codeString: String {
        get {
            withUnsafePointer(to: bigEndian) { pointer in
                pointer.withMemoryRebound(to: UInt8.self, capacity: Self.bytesSize) { bytes in
                    String(bytes: UnsafeBufferPointer(start: bytes,
                                                      count: Self.bytesSize),
                           encoding: .macOSRoman)!
                }
            }
        }
    }
}

extension OSStatus {
    var codeString: String {
        FourCharCode(bitPattern: self).codeString
    }
}

private func fourChars(_ string: String) -> String? {
    string.count == MemoryLayout<FourCharCode>.size ? string : nil
}
private func fourBytes(_ string: String) -> Data? {
    fourChars(string)?.data(using: .macOSRoman, allowLossyConversion: false)
}
func stringCode(_ string: String) -> FourCharCode {
    fourBytes(string)?.withUnsafeBytes { $0.load(as: FourCharCode.self).byteSwapped } ?? 0
}

它对我在macOS和iOS上均有效,并且与内置macOS NSFileTypeForHFSTypeCodeNSHFSTypeCodeFromFileType的行为非常匹配

一些陷阱:

  1. 使用bigEndianbyteSwapped
  2. 使用macOSRoman编码
  3. 通过返回0来处理长字符串,例如NSHFSTypeCodeFromFileType

以上实现与标准库方法的区别:

  1. NSFileTypeForHFSTypeCode在字符串NSFileTypeForHFSTypeCode(OSType(kAudioCodecBadDataError))) == "'bada'"周围添加额外的单引号。我已选择只返回bada
  2. 它无法产生中间带有\0的字符串,就像NSFileTypeForHFSTypeCode(kAudioFormatMicrosoftGSM)中的应该是ms\01,但返回'ms

答案 5 :(得分:2)

我为我的音频代码写了这个C函数......它可能有点幼稚,但它对我来说做得很好:

NSString* fourCharNSStringForFourCharCode(FourCharCode aCode){

char fourChar[5] = {(aCode >> 24) & 0xFF, (aCode >> 16) & 0xFF, (aCode >> 8) & 0xFF, aCode & 0xFF, 0};

NSString *fourCharString = [NSString stringWithCString:fourChar encoding:NSUTF8StringEncoding];

return fourCharString; }

答案 6 :(得分:1)

我建议使用这样的函数:

static NSString * NSStringFromCode(UInt32 code)
{
    UInt8 chars[4];
    *(UInt32 *)chars = code;
    for(UInt32 i = 0; i < 4; ++i)
    {
        if(!isprint(chars[i]))
        {
            return [NSString stringWithFormat:@"%u", code];
        }
    }
    return [NSString stringWithFormat:@"%c%c%c%c", chars[3], chars[2], chars[1], chars[0]];
}

这样可以确保您不会得到某些实际数字为kCMPixelFormat_32ARGB = 32的FourCharCodes的随机结果。

答案 7 :(得分:1)

如果您正在为macOS而不是iOS开发,那么在Launch Services中已经有了内置功能。要将4cc作为NSString:

(__bridge_transfer NSString *)UTCreateStringForOSType(fourccInt)

答案 8 :(得分:0)

使用Swift 2.2版本作为两个扩展:

extension String {
    public var fourCharCode:FourCharCode {
        var string = self
        if unicodeScalars.count < 4 {
            string = self + "    "
        }
        string = string.substringToIndex(string.startIndex.advancedBy(4))

        var res:FourCharCode = 0
        for unicodeScalar in string.unicodeScalars {
            res = (res << 8) + (FourCharCode(unicodeScalar) & 255)
        }

        return res
    }
}

extension FourCharCode {
    public var string:String {
        var res = String (UnicodeScalar((self >> 24) & 255))
        res.append(UnicodeScalar((self >> 16) & 255))
        res.append(UnicodeScalar((self >> 8) & 255))
        res.append(UnicodeScalar(self & 255))
        return res
    }
}

答案 9 :(得分:0)

这是j.s.com代码的Swift 3版本,为了消除重复而进行了清理:

func debugPrintFourCcCode(_ value: Int) {
  var res = ""

  if value <= 0x28 {
    res = "\(value)"
  } else {
    func add(_ pos: Int) {
      res.append(String(UnicodeScalar((value >> pos) & 255)!))
    }

    add(24)
    add(16)
    add(8)
    add(0)
  }

  NSLog("Code: \(res)")
}

答案 10 :(得分:0)

  
      
  • 处理不同的字节序体系结构
  •   
  • iOS和MacOS(
  •   
  • 易于理解
  •   
  • 即使使用8位字符,结果字符串(也应与OSType相同)
  •   
#import <Cocoa/Cocoa.h>
#import <CoreServices/CoreServices.h> // for EndianU32_NtoB
@implementation NSString (FourCC)

+ (NSString *) stringFromFourCC: (OSType) cccc
{
NSString * result = nil;
cccc = EndianU32_NtoB(cccc); // convert to network byte order, if needed
NSData * data = [NSData dataWithBytes: &cccc length: sizeof(OSType)];
result = [[NSString alloc] initWithData: data encoding: NSWindowsCP1252StringEncoding]; // lossless 8-bit encoding, could also use NSMacOSRomanStringEncoding
return result;
}

答案 11 :(得分:0)

一个非常简单的Mac版本,但不适用于iOS:

extension FourCharCode { // or `OSType`, or `UInt32`

    func stringValue() -> String {
        NSFileTypeForHFSTypeCode(self).replacingOccurrences(of: "\'", with: "")
    }

}

答案 12 :(得分:0)

Tricksy Swift版本:

func convert(fileType: OSType) -> String {
    let chars = [24, 16, 8, 0].map { Character(UnicodeScalar(UInt8(fileType >> $0 & 0xFF)))}
    return String(chars)
}

我已经在Swift 5上进行了测试,但是应该可以在以前的Swift版本上使用。

答案 13 :(得分:0)

public extension UInt32 {
    var string: String {
        String([
            Character(Unicode.Scalar(self >> 24 & 0xFF) ?? "?"),
            Character(Unicode.Scalar(self >> 16 & 0xFF) ?? "?"),
            Character(Unicode.Scalar(self >> 8 & 0xFF) ?? "?"),
            Character(Unicode.Scalar(self & 0xFF) ?? "?")
        ])
    }
}