這是Cocoa在幕後做所有雜亂的東西的其中一件事情,在你必須自己捲起袖子並自己動手才能做到這一點之前,你從不真正理解事情的複雜程度。
爲什麼它不是'簡單'的簡單答案是因爲NSString
(和CFString
)處理處理多個字符集,Unicode等等的所有複雜細節,同時呈現一個簡單的統一API來處理字符串。它最好以對象爲導向 - 'how'(NS|CF)String
處理具有不同字符串編碼的字符串(UTF8,MacRoman,UTF16,ISO 2022 Japanese等)的細節是一個私有實現細節。這一切都「正常」。
它有助於瞭解[@"..." UTF8String]
如何工作。這是一個私人的實現細節,所以這不是福音,而是基於觀察到的行爲。當您發送一個字符串UTF8String
消息,該字符串做了近似(沒有實際測試過,所以認爲這是僞代碼,而且也確實簡單的方式做同樣的事情,所以這是過於冗長):
- (const char *)UTF8String
{
NSUInteger utf8Length = [self lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
NSMutableData *utf8Data = [NSMutableData dataWithLength:utf8Length + 1UL];
char *utf8Bytes = [utf8Data mutableBytes];
[self getBytes:utf8Bytes
maxLength:utf8Length
usedLength:NULL
encoding:NSUTF8StringEncoding
options:0UL
range:NSMakeRange(0UL, [self length])
remainingRange:NULL];
return(utf8Bytes);
}
因爲NSMutableData
是自動發佈的,所以您不必擔心處理緩衝區的內存管理問題,因爲該緩衝區會返回-UTF8String
。
一個字符串對象可以自由地以任何形式保留字符串內容,所以不能保證它的內部表示是最適合您需要的內容表示(在這種情況下是UTF8)。如果您只使用普通的C語言,那麼您將不得不處理管理某些內存以保存可能需要的任何字符串轉換。曾經是簡單的-UTF8String
方法調用現在非常複雜得多。
大多數NSString
中/實際上是實現與的CoreFoundation/CFString
,所以很明顯有從CFStringRef
的路徑 - >-UTF8String
。它只是不如NSString
的-UTF8String
簡潔而簡單。大部分的複雜情況都與內存管理有關。下面是我如何在過去解決它:
void someFunction(void) {
CFStringRef cfString; // Assumes 'cfString' points to a (NS|CF)String.
const char *useUTF8StringPtr = NULL;
UInt8 *freeUTF8StringPtr = NULL;
CFIndex stringLength = CFStringGetLength(cfString), usedBytes = 0L;
if((useUTF8StringPtr = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8)) == NULL) {
if((freeUTF8StringPtr = malloc(stringLength + 1L)) != NULL) {
CFStringGetBytes(cfString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', false, freeUTF8StringPtr, stringLength, &usedBytes);
freeUTF8StringPtr[usedBytes] = 0;
useUTF8StringPtr = (const char *)freeUTF8StringPtr;
}
}
long utf8Length = (long)((freeUTF8StringPtr != NULL) ? usedBytes : stringLength);
if(useUTF8StringPtr != NULL) {
// useUTF8StringPtr points to a NULL terminated UTF8 encoded string.
// utf8Length contains the length of the UTF8 string.
// ... do something with useUTF8StringPtr ...
}
if(freeUTF8StringPtr != NULL) { free(freeUTF8StringPtr); freeUTF8StringPtr = NULL; }
}
注意:我還沒有測試此代碼,但它是從工作的代碼修改。所以,除了明顯的錯誤,我相信它應該起作用。
以上嘗試獲取指向CFString
用於存儲字符串內容的緩衝區的指針。如果CFString
恰好具有以UTF8編碼的字符串內容(或適當兼容的編碼,如ASCII),那麼很可能CFStringGetCStringPtr()
將返回非NULL
。這顯然是最好的,最快的案例。如果出於某種原因無法獲得該指針,請說明如果CFString
的內容以UTF16編碼,則它將分配一個包含malloc()
的緩衝區,該緩衝區的大小足以在將其轉碼爲UTF8時包含整個字符串。然後,在函數結束時,它會檢查內存是否被分配,如果有必要的話。
現在有一些提示和技巧... CFString
'傾向於'(這是一個私人實現細節,所以它可以並且確實在版本之間變化)保留'簡單'字符串編碼爲MacRoman,這是一個8位寬編碼。像UTF8一樣,MacRoman是ASCII的超集,因此所有的字符< 128等同於它們的ASCII對應字符(或換句話說,任何字符< 128是ASCII)。在MacRoman中,字符> = 128是'特殊'字符。它們都具有Unicode等價物,並且傾向於是額外的貨幣符號和「擴展的西方」字符。有關更多信息,請參閱Wikipedia - MacRoman。但僅僅因爲CFString
表示它是MacRoman(CFString
編碼值kCFStringEncodingMacRoman
,NSString
編碼值NSMacOSRomanStringEncoding
)並不意味着它的字符> = 128。如果由CFStringGetCStringPtr()
返回的kCFStringEncodingMacRoman
編碼的字符串完全由字符< 128組成,則它完全等同於其ASCII(kCFStringEncodingASCII
)編碼表示,其也完全等同於字符串UTF8(kCFStringEncodingUTF8
)編碼表示。
根據您的要求,當致電CFStringGetCStringPtr()
時,您可能可以使用kCFStringEncodingMacRoman
而不是kCFStringEncodingUTF8
。如果您需要對字符串進行嚴格的UTF8編碼,但使用kCFStringEncodingMacRoman
,然後檢查以確保由CFStringGetCStringPtr(string, kCFStringEncodingMacRoman)
返回的字符串僅包含< 128的字符,則'可能'(可能)會更快。如果字符串中包含字符> = 128 ,然後通過一個緩衝區來緩存路由,以保存轉換後的結果。例如:
CFIndex stringLength = CFStringGetLength(cfString), usedBytes = 0L;
useUTF8StringPtr = CFStringGetCStringPtr(cfString, kCFStringEncodingUTF8);
for(CFIndex idx = 0L; (useUTF8String != NULL) && (useUTF8String[idx] != 0); idx++) {
if(useUTF8String[idx] >= 128) { useUTF8String = NULL; }
}
if((useUTF8String == NULL) && ((freeUTF8StringPtr = malloc(stringLength + 1L)) != NULL)) {
CFStringGetBytes(cfString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', false, freeUTF8StringPtr, stringLength, &usedBytes);
freeUTF8StringPtr[usedBytes] = 0;
useUTF8StringPtr = (const char *)freeUTF8StringPtr;
}
就像我說的,你真的不明白可可到底有多少工作呢自動爲你,直到你必須自己做這一切。:)
現在,這是一個解釋! Thanx Johne!我試過你的代碼,現在我有另一個問題。因爲我以一個「.m」文件開始使用ObjC,所以我能夠快速地模擬一個例子。如今,我將轉換爲C++使用 「.mm」 文件我得到的構建例外: 未定義的符號: 「___gxx_personality_v0」,從引用: ___在libMyNetworking.a(MyLowLevelNetworking.o)gxx_personality_v0 $ non_lazy_ptr LD:符號(s)not found 我仍然覺得蘋果工具有時毫無頭緒...... – Cliff 2009-10-23 13:18:28