IOS/C: конвертировать "целое число" в четыре строки символов

Многие константы, связанные с программированием аудиосеансов, действительно представляют собой четырехсимвольные строки (Справочник по сеансам аудиосвязи). То же самое относится к OSStatus code, возвращаемому из таких функций, как AudioSessionGetProperty.

Проблема в том, что когда я пытаюсь напечатать эти вещи из коробки, они выглядят как 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 не очень сильный, но я подозреваю, что приведенный выше код пытается интерпретировать адрес памяти как строку. Или, может быть, проблема с кодировкой? Любые идеи?

Ответ 1

Тип, о котором вы говорите, это FourCharCode, определенный в CFBase.h. Это эквивалентно a OSType. Самый простой способ конвертировать между OSType и NSString использует NSFileTypeForHFSTypeCode() и NSHFSTypeCodeFromFileType(). Эти функции, к сожалению, недоступны в iOS.

Для iOS и Cocoa -портативного кода мне нравится Joachim Bengtsson's FourCC2Str() из NCCommon.h (плюс небольшая очистка для облегчения использования):

#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));

Конечно, вы могли бы бросить @() в макрос для более удобного использования.

Ответ 2

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

Ответ 3

Целое число = 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);

Ответ 4

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

Ответ 5

Я написал эту функцию 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

Я предлагаю использовать такую ​​функцию:

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]];
}

Это гарантирует, что вы не получите некоторых случайных результатов для некоторых FourCharCodes, которые являются фактическими числами, например kCMPixelFormat_32ARGB = 32.

Ответ 7

Если вы разрабатываете macOS, а не iOS, в Launch Services уже есть встроенная функция. Чтобы получить 4cc как NSString:

(__bridge_transfer NSString *)UTCreateStringForOSType(fourccInt)

Ответ 8

Более Swifty реализация, работающая для Swift 4:

extension String {
    init(fourCharCode: FourCharCode) {
        let n = Int(fourCharCode)
        var s: String = ""

        let unicodes = [UnicodeScalar((n >> 24) & 255), UnicodeScalar((n >> 16) & 255), UnicodeScalar((n >> 8) & 255), UnicodeScalar(n & 255)]
        unicodes.flatMap { (unicode) -> String? in
            guard let unicode = unicode else { return nil }
            return String(unicode)
        }.forEach { (unicode) in
            s.append(unicode)
        }

        self = s.trimmingCharacters(in: CharacterSet.whitespaces)
    }
}

Который может использоваться следующим образом:

String(fourCharCode: CMFormatDescriptionGetMediaSubType(charCode))

Ответ 9

  •    Работает с различными архитектурами с прямым порядком байтов
  • iOS и MacOS (и другие)
  • Легко понять
  • Результирующая строка (должна быть) идентична OSType даже с 8-битными символами
#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;
}

Ответ 10

Рабочая версия 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
    }
}

Ответ 11

Здесь версия Swift 3 кода j.s.com, очищенная для устранения повторения:

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

Ответ 12

Очень простая версия для Mac, но не для iOS:

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

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

}