3

次のコードを検討してください。

NSString *string = @"ä";
const char *str1 = [string cStringUsingEncoding:NSUTF8StringEncoding];
const char *str2 = "ä";
NSLog(@"C string comparison: %d",strcmp(str1,str2));
NSLog(@"str1: \"%s\"", str1);
NSLog(@"str2: \"%s\"", str2);

まったく新しい Foundation プロジェクトから実行すると、このプログラムは次のように出力します。

C string comparison: 0
str1: "ä"
str2: "ä"

文字列は同じであるはずなので、これは実際に私が期待していることです。

ただし、このまったく同じコードを別のコードベースの奥深くで実行すると、次の出力が得られます。

C string comparison: 31
str1: "ä"
str2: "ä"

この違いを説明できるものは何でしょうか? 両方のファイルが UTF-8 エンコーディングであると確信しています。それ -- 異なるファイル エンコーディング -- が、この動作の唯一の可能な説明ですよね?

2番目のケースで何がうまくいかなかったのか、何か考えはありますか? どうすれば修正できますか?

(2 番目のケースでは、コードが.mmファイル内、つまり Objective-C++ の下で実行されていることを言及しておく必要があります。これで説明できますか?)

4

3 に答える 3

2

代わりに、キャラクターの Unicode バージョンを使用してみてはいかがでしょうか?

すなわち

NSString * string1 = @"\u00e4" ;

参照。http://blog.ablepear.com/2010/07/objective-c-tuesdays-unicode-string.html

于 2012-05-21T22:20:21.413 に答える
0

ドキュメントから:

返された C 文字列は、レシーバーが解放されるか、現在の自動解放プールが空になるまでのいずれか早い方まで有効であることが保証されます。

あなたの場合、レシーバーが解放されているか、現在の自動解放プールが空になっていると思います。
例えば

NSString *string = @"ä";
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
const char *str3 = [string cStringUsingEncoding:NSUTF8StringEncoding];
[pool release];
NSLog(@"str1: \"%s\"", str3);
const char *str2 = "ä";
NSLog(@"C string comparison: %d",strcmp(str3,str2));
NSLog(@"str2: \"%s\"", str2);  

出力は

2012-05-22 17:14:50.069 test[32895:a0f] str1: "ä"
2012-05-22 17:14:50.071 test[32895:a0f] C string comparison: -195
2012-05-22 17:14:50.074 test[32895:a0f] str2: "ä" 



NSString *string = @"ä";
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
const char *str3 = [string cStringUsingEncoding:NSUTF8StringEncoding];
[pool release];
const char *str2 = "ä";
NSLog(@"C string comparison: %d",strcmp(str3,str2));
NSLog(@"str1: \"%s\"", str3);
NSLog(@"str2: \"%s\"", str2);

出力は

2012-05-22 17:19:13.226 test[33153:a0f] C string comparison: 0
2012-05-22 17:19:13.228 test[33153:a0f] str1: ""
2012-05-22 17:19:13.229 test[33153:a0f] str2: "ä"
于 2012-05-22T11:50:35.530 に答える
0

ソース ファイルがディスク上でどのようにエンコードされるかは 1 つの問題です。コンパイラがそれがエンコードされているとどのように認識するかは別ですデフォルトでは、GCC は UTF-8 を想定していますが、ロケールまたは-finput-charset=<charset>オプションからの別のエンコーディングであることがわかります。Clang も同じことをサポートしていると思います。

Xcode には、ソース ファイルのエンコーディングに関する独自の概念があります。上記のオプションを使用してそれを渡すようにコンパイルコマンドを調整するかどうかはわかりませんが、驚かないでしょう。

GCC には、実行文字セットの概念もあります。これは、文字列をバイナリに書き込む方法です。-fexec-charset=<charset>オプションを参照してください。

そのため、コンパイラは入力文字セットに従ってファイルのバイトを解釈し、実行文字セットでバイナリに書き込みます。この 2 つが異なる場合は、変換が必要です。これは翻訳単位ごとに発生する問題であるため、ソース ファイルごとに異なる方法で発生する可能性があります。

もう 1 つの問題は、"ä" が Unicode で 2 つの可能な表現を持つことです。LATIN SMALL LETTER A WITH DIAERESIS (U+00E4) または LATIN SMALL LETTER A (U+0061) の後に COMBINING DIAERESIS (U+0308) を指定できます。UTF-8 では、0xC3 0xA4 対 0x61 0xCC 0x88 になります。2 つのソース ファイルが同じ文字を異なる方法で表現している可能性があります。つまり、実際には異なる文字列が含まれていることを意味します (すべてのレベルで: C 文字列、NSStringなど。ただし、が指定されていない場合、メソッドNSStringの違いは無視されます。ただし、メソッドはリテラル比較を行います)。 )。もちろん、これらの 2 つのバイト シーケンスが異なる方法でエンコーディング間で変換されている場合、これは悪化します。-compare:...NSLiteralSearch-isEqual...

そのため、関連する文字列を含む特定のソース ファイルを追跡する必要があります。含まれているバイトを正確に 16 進ダンプで確認してください。それらをコンパイルするために使用されたコマンド (およびロケールが役割を果たす可能性がある場合は環境) をチェックして、コンパイラが入力および実行可能文字セットについて何を信じているかを確認します。

于 2012-05-21T23:01:33.063 に答える