VS2019 报错“常量中有换行符” 错误原因分析

最近用VS2019写C++时候发现一个问题,在代码中直接写中文,有一部分汉字会报错,提示“常量中有换行符”。解决方法一搜就有了,因为文件编码是UTF-8,所以在编译选项里面加一个/utf-8就能解决。你也可以说中文不能这么写,要用宽字符之类的。当然解决问题不是这篇文章的重点,我们需要搞清楚为什么有这个报错。

环境是:cpp文件使用UTF-8编码,用VS2019自带的MSVC编译器,不做任何编译选项的设置。首先说一下已知的几种情况:

1.代码 printf("世") 会报错“常量中有换行符”。

2.在"世"后面加一个半角空格,错误提示没了,但是会提示警告"该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失"。

3.在"世"后面加一个全角空格,错误提示没了,警告也没了。

为了更好地分析问题,我们把这三个字符数组打印出来

VS2019 报错“常量中有换行符” 错误原因分析_第1张图片

这三种情况都是有编码问题,总的来说,问题在于MSVC认为的编码和文件实际的编码不一致,导致解析的结果不对。MSVC在默认情况下是用系统编码,在简体中文的Win10系统中,默认编码就是GBK,所以,MSVC默认把文件当做GBK编码读入,然后导致了这几种情况。

GBK的编码规则是:双字节表示,总体编码范围为 0x8140-0xFEFE,首字节在 0x81-0xFE 之间,尾字节在 0x40-0xFE 之间,剔除 0xxx7F 一条线。

下面对表格中几种情况的解释:

  情况1,MSVC读取前两个字节0xE4B8,认为这是一个GBK字符"涓",然后读取0x96,这个字节在GBK的首字节范围(0x81-0xFE)之内,所以MSVC认为这是个双字节汉字,后面还有一个字节。但是接着就读取到了引号,这个字符串已经结束,这不符合GBK的编码规则,所以编译出错。

  情况2,在1的情况下读取0x96之后,MSVC期待读入GBK编码的尾字节(0x40-0xFE),但是接下来读取到的0x20不在这个范围内,这不是个合法的GBK字符,所以MSVC把第一个字节0x96强制改为0x3F,即ASCII编码的问号,然后丢弃第二个字节0x20,继续编译,提示一个警告表示编码有问题。

  情况3,在1的情况下读取0x96之后,MSVC期待读入GBK编码的尾字节(0x40-0xFE),然后读取到0xE3,MSVC认为这两个字节是GBK的汉字'栥'。之后的两个字节,MSVC认为这是字符'€',至于0x80如何映射到这个符号,可以参考Wiki的Windows 1252编码,最后遇到引号,所以这是个合法的GBK字符串,MSVC直接把读取到的字节原样放到数组里面,没有任何报错。

  这样分析以后,其实可以对情况3下结论了。为了不让编译报错,最后加全角空格是一种比较取巧的做法,只是因为全角空格的第一个字节0xE3能和前一个字节能组成合法的GBK汉字。从GBK的编码规则看,其实后面接上任意的编码在0x40-0xFE之间的字符,都能通过编译且不提示任何报错,比如'A', 'B',但是'1'就不行。当然我们要明确问题在哪,这是编码设置的错,直接修改编译选项就能解决问题,这种取巧的方法没多少实用价值。

  针对编码,MSVC有专门的编译选项/source-charset 和 /execution-charset,前者表示文件本身的编码,后者表示编译以后的字符数组内的字节是什么编码,编码问题基本可以用这两个选项解决。

  比如,Windows的cmd控制台默认只能显示GBK编码,但是代码文件本身是UTF-8,因为跨平台的缘故,又不方便直接修改成GBK,当然这里就不包括为不同平台写编码转换代码这种办法。在Win10上,可以设置这两个编译选项为/source-charset:utf-8 /execution-charset:gbk,表示让编译器以UTF-8编码读入,然后转为GBK保存在数组里面,这样直接printf就能在cmd控制台上正常显示汉字。

  此外,EA在最近公开了红警1的部分代码,这个代码的编码是代码页850的,我们通过微软的文档找到这个编码叫做ibm850,所以用编译选项 /source-charset:ibm850 /execution-charset:ibm850,就能解决编码问题。当然这样修改以后还是只能编译,不方便编辑文件,最根本的解决办法是只能麻烦一点,把文件转成UTF-8编码,这样编译和编辑都没问题。

你可能感兴趣的:(计算机相关,c++,开发语言)