许多与音频会话编程相关的常量实际上是四个字符的字符串(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不是很强,但我的预感是上面的代码试图将内存地址解释为字符串。或者可能存在编码问题?有什么想法吗?
答案 0 :(得分:16)
您所谈论的类型是FourCharCode
,在CFBase.h
中定义。它等同于OSType
。在OSType
和NSString
之间进行转换的最简单方法是使用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 NSFileTypeForHFSTypeCode
和NSHFSTypeCodeFromFileType
的行为非常匹配
一些陷阱:
bigEndian
和byteSwapped
macOSRoman
编码NSHFSTypeCodeFromFileType
以上实现与标准库方法的区别:
NSFileTypeForHFSTypeCode
在字符串NSFileTypeForHFSTypeCode(OSType(kAudioCodecBadDataError))) == "'bada'"
周围添加额外的单引号。我已选择只返回bada
\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) ?? "?")
])
}
}