为什么VS编译UTF-8格式源代码, 代码中字符串却是ANSI编码?如何快速获取字符串的UTF-8或UTF-16编码二进制数据?Java .class文件编码和JVM运行期内存编码?字符串默认编码?

目录

为什么VS编译UTF-8格式源代码, 代码中字符串却是ANSI编码?

如何快速获取字符串的UTF-8或UTF-16编码二进制数据?

Java .class文件编码和JVM运行期内存编码

字符串默认编码

Swift字符串默认编码

VS如何编译没有BOM头的UTF-8源代码?

为什么中文字符串会报出错误"C2001: 常量中有换行符"?


为什么VS编译UTF-8格式源代码, 代码中字符串却是ANSI编码?

说到底,问题的根源在于源代码编码是给编译器看的,可以是任何编码,只要编译器支持的编码就可以,最终生成机器码不存在编码一说。但,源代码中的字符串是实打实会交给控制台或者GUI程序展示,它的编码正确性很重要,一旦不匹配就很可能乱码。所以,源代码中字符串的编码,编译器一般采用贴近本机操作系统的默认编码,Windows当然是ANSI编码,Linux平台一般为UTF-8编码。这就出现和源代码编码不一致的情况了。例如,OS默认是ANSI编码,UTF-8格式源代码,字符串"我"在VC编译依然是GB2312编码CE D2. 假设字符串变量出现在如下demo.c中:

  • cl /source-charset:utf-8 demo.c "我"对应: CE D2.
  • cl /utf-8 demo.c "我"是UTF-8编码,对应: E6 88 91.
  • cl /execution-charset:gb2312 demo.c "我"对应: CE D2.
  • cl /execution-charset:utf-8 demo.c "我"是UTF-8编码,对应: E6 88 91.

如何快速获取字符串的UTF-8或UTF-16编码二进制数据?

  • 在线字符编码转换网站
  • Swift提供了非常简洁的编码二进制数据查看方法
    let s = "a我a"
    s.utf8.forEach { print($0, terminator: " ") } // UTF-8: 97 230 136 145 97
    s.utf16.forEach { print($0, terminator: " ") }
     // UTF-16: 97 25105 97

Java .class文件编码和JVM运行期内存编码

  • Java源代码可以是任意编码格式,javac需要指定编码格式-encoding即可正确编译。
  • javac编译出.class文件是UTF-8编码。
  • JVM读取.class文件加载到内存中,编码格式为UTF-16.
  • java执行.class文件使用默认字符串输出(Windows平台是GBK),如对应的终端或显示设备编码不同,使用-Dfile.encoding=xxx指定编码。

字符串默认编码

随着编程语言逐渐国际化,字符串并不总是早期的ASCII码,中文也逐渐进入编程语言的世界。不同编程语言和编译器因设计差异,字符串默认编码也可能存在差异。

  • GCC/G++/Clang/Clang++编译的C/C++代码默认字符串为UTF-8编码,MSVC默认字符串为ANSI编码。ObjC编译器是GCC或Clang, 跟随编译器的特性,NSString字符串默认编码也是UTF-8.
    • 可通过objdump -x -s a.out获取字符串常量的数值。
  • Rust字符串默认编码也是UTF-8编码,可用str.as_bytes()获取原始数据。
  • Swift 5之前字符串默认编码是ASCII(如果字符串每个字符都是ASCII码)和UTF-16,Swift 5之后(包含)默认编码为UTF-8.
  • Go默认字符串原始数据为UTF-8编码,通过[]byte(str)获取原始字节数据。
  • Java/C#字符串原始数据是UTF-16编码(字符串被加载到内存中的编码),尽管java编译出.class文件可能是UTF-8编码。

Swift字符串默认编码

Swift 5之前,有UTF-16(Unicode)和 ASCII 两种编码方式,Swift 5之后改成UTF-8编码格式。

Swift.org - UTF-8 String

VS如何编译没有BOM头的UTF-8源代码?

可参考 为什么中文字符串会报出错误”C2001: 常量中有换行符”? 利用/utf-8或者/source-charset:utf-8解决此问题。不同之处是/utf-8还指定了执行编码集为UTF-8:/execution-charset:utf-8.

为什么中文字符串会报出错误"C2001: 常量中有换行符"?

如果是用VS,一种很大的可能是VS没有正确识别源代码编码格式,比如是UTF-8格式,no BOM. VS没有发现UTF-8或UTF-16的BOM头,会默认按ANSI编码(中文操作系统默认是GB2312)解析源代码,包括源代码中的字符串,即将UTF-8格式的字符串字节用GB2312来解析,自然可能会产生问题。

即使在VS的设置中增加额外选项"/utf-8"依然不能编译通过(VS2022 17.0.4, 这与微软官方文档的说法不一致),不过可以在命令行中加/utf-8消除问题,例如cl /utf-8 demo.c, 怀疑这是VS的一个bug.


若文章对您有帮助,欢迎关注 程序员小迷 。助您在编程路上越走越好!

微风不燥,阳光正好,你就像风一样经过这里,愿你停留的片刻温暖舒心。

我是 程序员小迷 (致力于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享),若作品对您有帮助,请关注、分享、点赞、收藏、在看、喜欢,您的支持是我们为您提供帮助的最大动力。

1.您还可以访问 迷软科技 网站:https://www.minicoda.com

2.想学习更多知识,您可以关注 微信公众号程序员小迷miniminicode )(一个关注于C、C++、C#、Android、iOS、Java、Kotlin、Objective-C、Swift等语言软件开发技能技巧经验的公众号)

你可能感兴趣的:(为什么VS编译UTF-8格式源代码, 代码中字符串却是ANSI编码?如何快速获取字符串的UTF-8或UTF-16编码二进制数据?Java .class文件编码和JVM运行期内存编码?字符串默认编码?)