C源文件中的可移植文字字符串

时间:2013-04-06 09:27:05

标签: c string utf-8 utf-16

好的,我有这个:

AllocConsole();
SetConsoleOutputCP(CP_UTF8);
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
WriteConsoleA(consoleHandle, "aΕλληνικά\n", 10, NULL, NULL);
WriteConsoleW(consoleHandle, L"wΕλληνικά\n", 10, NULL, NULL);
printf("aΕλληνικά\n");
wprintf(L"wΕλληνικά\n");

现在,问题是根据编码文件保存为只有一些这些工作。 wprintf永远不会工作,但我已经知道为什么(破坏的Microsoft stdout实现,只接受狭窄的字符)。然而,我和另外三个人有问题。如果我将文件保存为UTF-8而没有签名(BOM)并使用MS Visual C ++编译器,则只有最后一个printf可以工作。如果我想要ANSI版本工作,我需要将字符(?)计数增加到18:

WriteConsoleA(consoleHandle, "aΕλληνικά\n", 18, NULL, NULL);

WriteConsoleW不起作用,我假设,因为字符串保存为UTF-8字节序列,即使我明确要求它存储为带有L前缀的宽字符(UTF-16),并且实现最可能期望UTF-16编码的字符串不是UTF-8。

如果我用带有BOM的UTF-8保存它(应该是),那么WriteConsoleW开始以某种方式工作(???),其他一切都停止(我得到了?而不是一个字符)。我需要将WriteConsoleA中的字符数减少到10以保持格式相同(否则我得到8个额外的矩形)。基本上,WTF?

现在,我们转到UTF-16(Unicode - Codepage 1200)。仅适用于WriteConsoleW。 WriteConsoleA中的字符数应为10,以保持格式的精确。

以UTF-16 Big Endian模式保存(Unicode - 代码页1201)不会改变任何内容。再次,WTF?当存储到文件时,字符串内的字节顺序是否应该被反转?

结论是字符串编译成二进制形式的方式取决于使用的编码。因此,存储字符串的可移植和编译器独立方式是什么?是否有一个预处理器可以在编译之前将一个字符串表示转换为另一个字符串表示,因此我可以将文件存储为UTF-8,并且仅通过将它们包装为宏来预处理UTF-16中需要的字符串。

2 个答案:

答案 0 :(得分:0)

据我所知,我认为你至少有一些假设是错误的或者不是100%正确的:

  

现在,问题是根据编码文件保存为只有一些工作。

当然,因为编码决定了如何解释字符串文字。

  

wprintf永远不会有效,但我已经知道为什么(破坏的Microsoft stdout实现,它只接受狭窄的字符)。

我从来没有听说过那个,但我相信这取决于为你的程序设置的语言环境。我有一些工作项目,其中设置了语言环境,输出就可以使用德语变音符号等。

  

如果我将文件保存为UTF-8而没有签名(BOM)并使用MS Visual C ++编译器,则只有最后一个printf可以工作。如果我想要ANSI版本工作,我需要将字符(?)计数增加到18:

这是因为ANSI版本需要ANSI字符串,而您传递的是UTF-8编码字符串(基于文件的编码)。输出仍然有效,因为控制台为您处理UTF-8转换 - 您实际上是在这里打印原始UTF-8。

  

WriteConsoleW不起作用,我假设,因为字符串保存为UTF-8字节序列,即使我明确要求它存储为带有L前缀的宽字符(UTF-16),并且实现最可能期望UTF-16编码的字符串不是UTF-8。

我不这么认为(虽然我不确定为什么它也不起作用)。您是否尝试过设置一些易于查找的字符串并在生成的二进制文件中查找它?我很确定它确实是用UTF-16编码的。我假设由于缺少BOM,编译器可能会将整个事物解释为一个窄字符串,因此将UTF-8转换为错误。

  

如果我用带有BOM的UTF-8保存它(应该是),那么WriteConsoleW开始以某种方式工作(???),其他一切都停止(我得到了?而不是一个字符)。我需要将WriteConsoleA中的字符数减少到10以保持格式相同(否则我得到8个额外的矩形)。基本上,WTF?

这正是我上面所描述的。现在宽字符串被正确编码,因为编译器现在知道文件是UTF-8,而不是ANSI(或某些代码页)。窄字符串也正确转换为正在使用的语言环境。


总的来说,除非你事先使用正确的代码页和/或UTF代码逃避所有事情,否则没有独立的编码方式。我只是坚持使用带有BOM的UTF-8,因为我认为所有当前的编译器都能够正确读取和解释文件(除了微软的资源编译器之外;虽然我没有尝试用UTF-8提供2012版本)。

编辑:

使用类比:

您实际上是将原始图像保存到文件中,并且您希望它能够正常工作,无论其他程序是否尝试将其作为灰度,调色板或全彩图像读取。这不起作用(尽管差异较小)。

答案 1 :(得分:0)

答案是here

引用:

  

编译器无法混合使用UTF-8和UTF-16   字符串到编译输出!所以你必须决定一个来源   代码文件:

     
      
  • 使用带有BOM的UTF-8并仅生成UTF-16字符串(即始终使用L前缀),
  •   
  • 或UTF-8没有BOM并仅生成UTF-8字符串(即从不使用L前缀),
  •   
  • 不涉及7位ASCII字符,可以使用或不使用L前缀
  •   

唯一的可移植和编译器独立方式是使用ASCII字符集和转义序列,因为不能保证任何编译器都接受UTF-8编码文件,并且这些多字节序列的编译器处理可能会有所不同。