最近在把我用 C 写的一批 Linux 工具移植到 Windows 上,在字符编码上遇到了大坑。
举个简单的例子:数文件层级。
在 Linux 上,我们数斜杠数量就好。
在 Windows 上,再加上反斜杠,应该就好了。——我是这样想的。
#include <stdio.h>
int main(int argc, char *argv[]) {
int level;
const char *p;
if (argc < 2) {
return 1;
}
for (level = 0, p = argv[1]; *p; p++) {
if (*p == '/' || *p == '\\') {
level++;
}
}
printf("%d\n", level);
return 0;
}
用 MinGW 的 GCC 编译一下,然后跑几个用例:
gcc -o getlevel.exe getlevel.c
C:\>getlevel C:\浙江省\宁波市\北仑区\小港街道.txt
4
C:\>getlevel C:\浙江省\宁波市\北仑区\大碶街道.txt
5
天塌了,这么简单的代码竟然出了 bug 。
原来 碶
的 编码是 {0xb4, 0x5c}
,其中 0x5c
和反斜杠的 ASCII 编码一模一样。
GBK 的第一字节兼容 ASCII ,但第二字节的范围是 0x40
~ 0xfe
,与 ASCII 的 0x00
~ 0x7f
重叠。BUG 就这么诞生了。
UTF-8 没有这个问题的原因是:只要字节范围在 0x00
~ 0x7f
,那么就一定是 ASCII ,因为后续字节都避开了这个范围。虽然中文编码比 GB 系列长了,但是这个设计确实省了很多事。包括 strstr()
strcmp()
之类的都不会出现奇奇怪怪的 bug 。
或许我应该使用 wmain()
然后获取 wchar_t
,但是 wmain()
是 Windows 特有的东西,这样做就没法和 Linux 公用同一套代码了。目前加上了 mbtowc()
作为修复。原本简洁的代码变得十分复杂:(
说到这又不得不吐槽下 Windows 的各种奇怪 API 了,不知道它是如何存活到现在的...
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.