Objective c 奇怪的C字符串和NSString比较问题 请考虑以下代码: 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); 如果从一个全新的基础项目运行,该程序输出: C string comparison: 0 str1: "√§" str2: "√§"

Objective c 奇怪的C字符串和NSString比较问题 请考虑以下代码: 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); 如果从一个全新的基础项目运行,该程序输出: C string comparison: 0 str1: "√§" str2: "√§",objective-c,c,string,cocoa,character-encoding,Objective C,C,String,Cocoa,Character Encoding,这确实是我所期望的,因为字符串应该是相同的 但是,如果我在另一个代码库的深处运行完全相同的代码,我会得到以下输出: C string comparison: 31 str1: "‚àö¬ß" str2: "√§" 有什么可能解释这种差异?我很确定这两个文件都是UTF-8编码的。不同的文件编码是这种行为的唯一可能解释,对吗 你知道第二个案子会出什么问题吗?我怎样才能修好它 (我可能应该提到,在第二种情况下,代码是在.mm文件中运行的,即在Objective-C++下运行的。这可以解释一下吗?您可

这确实是我所期望的,因为字符串应该是相同的

但是,如果我在另一个代码库的深处运行完全相同的代码,我会得到以下输出:

C string comparison: 31
str1: "ä"
str2: "ä"
有什么可能解释这种差异?我很确定这两个文件都是UTF-8编码的。不同的文件编码是这种行为的唯一可能解释,对吗

你知道第二个案子会出什么问题吗?我怎样才能修好它


(我可能应该提到,在第二种情况下,代码是在
.mm
文件中运行的,即在Objective-C++下运行的。这可以解释一下吗?

您可以尝试改用unicode版本的字符吗

i、 e


参见。

源文件如何在磁盘上编码是一回事。编译器认为它是如何编码的是另一个问题。默认情况下,GCC采用UTF-8,但可以通过区域设置或
-finput charset=
选项告诉它是另一种编码。我希望叮当声支持同样的事情

Xcode对源文件的编码有自己的概念。我不知道它是否会在使用上述选项时调整compile命令来传递它,但我不会感到惊讶

GCC还具有执行字符集的概念。这就是它将字符串写入二进制文件的方式。请参阅
-fexec charset=
选项

因此,编译器根据输入字符集解释文件的字节,并将它们写入执行字符集中的二进制文件。如果这两者不同,那么就需要转换。这是每个翻译单元的事务,因此对于不同的源文件,可能会发生不同的情况

另一个问题是“ä”在Unicode中有两种可能的表示形式。它可以是带分音符(U+00E4)的拉丁文小写字母A,也可以是后跟组合分音符(U+0308)的拉丁文小写字母A(U+0061)。在UTF-8中,这将是0xC3 0xA4,而不是0x61 0xCC 0x88。您的两个源文件可能以不同的方式表达相同的字符,这意味着它们确实包含不同的字符串(在所有级别:C string、
NSString
,尽管
NSString
将忽略
-compare:…
方法之间的差异,如果未指定
NSLiteralSearch
;但是
-isEqual…
方法执行文字比较)。当然,如果这两个字节的序列以不同的方式在编码之间转换,情况会更糟

因此,您需要跟踪包含相关字符串的特定源文件。使用十六进制转储检查它们包含的字节数。检查用于编译它们的命令(如果语言环境可能起作用,还可能检查环境)查看编译器对输入和可执行字符集的看法。

来源:

返回的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: "ä"

我会尝试记录第二种情况下实际比较的字符串。在记录字符串时,请确保在字符串周围加引号,以确保没有尾随空格。@Marvo谢谢,我相应地更改了我的问题。您说“完全相同的代码”但是,再提到一些文件,那么你真的在从文件中读取str1/str2吗?如果是,请仔细检查它们的编码,以100%确定它是UTF-8,并且你能展示一下如何将这些文件读入str1/str2吗?@OlivierLance的“文件”,我指的是源文件本身,即我粘贴代码的文件。我已经“检查”了通过在TextMate中打开它们,并在“文件->使用编码重新打开”下查看,可以进行编码菜单,我看到了UTF8之外的一个复选标记。有没有更复杂的方法来检查文件编码?另外,我假设在
NSLog
中%s格式说明符需要ASCII,但您传递的是非ASCII字符。事实上,我想我是对的。请看以下答案:@nielsbot谢谢,但这仍然不能解释为什么相同的代码会这样在不同的地方产生不同的行为…这是这里的主要问题…我认为这两个运行时环境可能期望将不同的编码传递给
%s
。在一种情况下,它期望MacRoman(但您传递的是UTF8)在另一种情况下,它需要UTF-8,因此工作正常。我链接的答案中提到了这一点。检查
CFStringGetSystemEncoding()
是否在两种运行时场景下返回不同的结果
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: "ä"