一个奇怪的C字符串和NSString比较问题

时间:2012-05-21 21:57:05

标签: objective-c c string cocoa character-encoding

请考虑以下代码:

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: "ä"

这确实是我期望发生的事情,因为字符串应该是相同的。

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

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

有什么可以解释这种差异?我很确定这两个文件都是UTF-8编码。那个 - 不同的文件编码 - 是这种行为唯一可能的解释,对吗?

任何想法在第二种情况下可能出错?我该如何解决?

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

3 个答案:

答案 0 :(得分:2)

您可以尝试使用角色的unicode版本吗?

NSString * string1 = @"\u00e4" ;

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

答案 1 :(得分:0)

如何在磁盘上编码源文件是一回事。编译器如何相信它是如何被编码的另一种。默认情况下,GCC采用UTF-8,但可以通过语言环境或-finput-charset=<charset>选项告诉它使用其他编码。我希望Clang支持同样的事情。

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

GCC还有一个执行字符集的概念。这就是它如何将字符串写入二进制文件。请参阅-fexec-charset=<charset>选项。

因此,编译器根据输入字符集解释文件的字节,并将它们写入执行字符集中的二进制文件。如果这两者不同,则涉及转换。这是一个单翻译单位事件,因此对于不同的源文件可能会有不同的情况。

另一个问题是“ä”在Unicode中有两种可能的表示形式。它可以是带有DIAERESIS的UATIN SMALL LETTER(U + 00E4),也可以是LATIN SMALL LETTER A(U + 0061),然后是COMBINING DIAERESIS(U + 0308)。在UTF-8中,这将是0xC3 0xA4与0x61 0xCC 0x88。您的两个源文件可能以不同的方式表示相同的字符,这意味着它们确实包含不同的字符串(在所有级别:C字符串,NSString,无论如何,尽管NSString将忽略{{1}的差异}如果未指定-compare:...,则方法; NSLiteralSearch方法进行文字比较。当然,如果这两个字节序列以不同方式在编码之间进行转换,这将会加剧。

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

答案 2 :(得分:0)

来自Documentation

  

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