11

我在普通 iPad 单视图应用程序的 viewDidLoad 函数中运行以下代码:

/*
 *  Print the string.  A lot.
 */
for (int i = 0; i < 300; i++) {
    NSLog(@"%d\n", i);
    NSLog(@"⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ \n");
}

输出如下所示:

2013-02-04 20:17:49.718 testplay[59585:c07] 228
2013-02-04 20:17:49.718 testplay[59585:c07] ⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ 
2013-02-04 20:17:49.719 testplay[59585:c07] 229
2013-02-04 20:17:49.719 testplay[59585:c07] ⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ 
2013-02-04 20:17:49.719 testplay[59585:c07] 230
2013-02-04 20:17:49.720 testplay[59585:c07] ⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ 
2013-02-04 20:17:49.720 testplay[59585:c07] 231
2013-02-04 20:17:49.720 testplay[59585:c07] ⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ \342\212\221 ⊒ 
2013-02-04 20:17:49.723 testplay[59585:c07] 232
2013-02-04 20:17:49.724 testplay[59585:c07] ⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ 

八进制几乎总是发生在同一个字符上,并且每次运行大约随机出现 3 次打嗝。

虽然它在 NSLog() 中相对无害,但它意味着 unicode 字符可能在某种程度上被不规则地处理。如果有这种行为的历史或我可以查看的某些资源,那就太好了。

[附录:删除了对我如何遇到此问题的参考。我希望了解 NSLog 为何以及如何读取损坏的 unicode 字符。]

4

2 回答 2

8

精简版:

我认为如果NSLog()输出的 UTF-8 序列恰好落在 Xcode 用于调试进程的标准错误的伪终端缓冲区的边界上,就会发生这种情况。

如果我的假设是正确的,这只是 Xcode 调试器输出的问题,并不意味着应用程序中存在任何 Unicode 问题。

长版:

如果您在模拟器中运行您的应用程序,则lsof -p <pid_of_simulated_app>显示标准错误(文件描述符 2)被重定向到伪终端:

# lsof -p 3251
...
testplay 3251 martin    2w     CHR               16,2     0t131     905 /dev/ttys002
...

lsof -p <pid_of_Xcode>显示 Xcode 打开了相同的伪终端:

# lsof -p 3202
...
Xcode   3202 martin   51u     CHR               16,2       0t0     905 /dev/ttys002
...

NSLog()写入标准错误。使用系统调用跟踪器“dtruss”可以看到 Xcode 从伪终端读取日志消息。对于单个日志消息

NSLog(@"⊢ ⊣ ⊥ ⊻ ⊼ ⊂ ⊃ ⊑ ⊒ \n");

它看起来像这样:

# dtruss -n Xcode -t read_nocancel
 3202/0xe101:  read_nocancel(0x31, "2013-02-05 08:57:44.744 testplay[3251:11303] \342\212\242 \342\212\243 ... \342\212\222 \n\0", 0x8000)       = 82 0

但是对于许多NSLog()快速相互跟随的语句,有时会发生以下情况:

# dtruss -n Xcode -t read_nocancel
...
 3202/0xd828:  read_nocancel(0x33, "2013-02-05 08:39:51.156 ...", 0x8000) = 1024 0
 3202/0xd87b:  read_nocancel(0x33, "\212\273 \342\212\274 ...", 0x8000) = 24 0

如您所见,Xcode 已经从伪终端读取了 1024 个字节,并且下一次读取以不完整的 UTF-8 序列开始。在这种情况下,Xcode“看不到”第​​一次读取的最后一个字节和第二次读取的前两个字节是同一 UTF-8 序列的一部分。我假设 Xcode 将所有 3 个字节视为无效的 UTF-8 序列并将它们打印为八进制数。

于 2013-02-05T08:21:45.640 回答
0

一种解决方法,在您的循环中,放置一个“fflush(stderr);” 在第二个 NSLog 语句之后;这将强制 stderr 在继续之前提交并写入缓冲区。

于 2013-02-07T00:58:28.343 回答