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