3

在 bash 中,我可以hello通过执行以下操作将字符串的十六进制转储为 UTF-16:

$  echo -n "hello" | iconv -f ascii -t utf-16 | hexdump
0000000 feff 0068 0065 006c 006c 006f          
000000c

我也可以像这样编写一个简短的 C 程序:

int main(int argc, char **argv) {
  char *str = argv[1];

  hexDump("The string", str, 12);

  return 0;
}

使用如何获取结构数据的 hexdump 中hexDump的例程。是我从上面的使用中计算出来的字节数。12hexdump

编译并运行:

$ gcc test.c -o test


$ ./test $(echo -n hello | iconv -f ascii -t utf-16)
The string:
  0000  ff fe 68 65 6c 6c 6f 00 53 53 48 5f              ..hello.SSH_

feff 0068 0065 006c 006c 006f为什么第一个 hexstring和第二个 hexstring之间有区别ff fe 68 65 6c 6c 6f 00 53 53 48 5f

我之所以问这个问题是因为我正在尝试调试一个libiconv用于将 UTF-16 字符串转换为 UTF-8 的应用程序,并不断得到其中的一个errnoEILSEQ这意味着libiconv遇到了“无效的多字节序列”。

更新:

如果我使用 运行hexdump-C我会得到以下输出:

$ echo -n hello | iconv -f ascii -t utf-16 | hexdump -C
00000000  ff fe 68 00 65 00 6c 00  6c 00 6f 00              |..h.e.l.l.o.|
0000000c

这个十六进制字符串仍然与我的 C 程序生成的不同,因为它包含\x00散布在 ascii 字符之间的字节。但是,当我运行 C 程序时,根本没有\x00散布任何字节。它只有ff fe标题,然后是常规的 ascii 字符。

4

1 回答 1

4

该命令echo -n hello | iconv -f ascii -t utf-16 | hexdump -C只是在程序之间直接管道数据。无论来自 iconv 的字节都直接作为 hexdump 的输入。

使用 command ./test $(echo -n hello | iconv -f ascii -t utf-16),shell 获取 iconv 的输出,并将其有效地粘贴到新命令中,解析新命令,然后执行它。

所以从 iconv 出来的字节是:“ff fe 68 00 65 00 6c 00 6c 00 6f 00”,shell 会解析它。看起来好像 shell 在解析时只是跳过了空字节,所以输入到程序的参数只是非空字节。由于您的字符串是 ascii,这意味着结果只是一个 ascii 字符串(前面是 UTF-16 BOM)。

我们可以使用像 U+3300 (㌀) 这样的字符来证明这一点。如果我们传递这个而不是 ascii 字符并且上面是正确的,那么输出将包括 0x33(数字 '3')。

./test $(echo -n ㌀ | iconv -f utf-8 -t utf-16)

我的终端碰巧使用支持字符 U+3300 的 UTF-8,所以我将 iconv 从它转换为 UTF-16。我得到输出:

The string:
  0000  ff fe 33                                         ..3

顺便说一句,您的程序包含数组的硬编码大小:

hexDump("The string", str, 12);

你真的不应该那样做。如果数组不是那么大,那么您会得到未定义的行为,并且您的帖子显示在真实参数之后打印出一些垃圾(垃圾似乎是环境变量数组的开头)。这真的没有理由。只需使用正确的值:

hexDump("The string", str, strlen(str));
于 2014-01-11T05:47:03.447 回答