V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
amiwrong123
V2EX  ›  程序员

vs 中如何解决 C++的“常量中有换行符”

  •  
  •   amiwrong123 · 2021-11-27 11:19:47 +08:00 · 3537 次点击
    这是一个创建于 873 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境:Windows 上使用 vs

    总是遇到那种定义一个中文字符串std::string = "你好";(不一定是这段中文),然后 vs 就编译报错“常量中有换行符”。

    我看了网上的文章,大概意思就是会收到这三个的影响:

    • 源文件本身的编码格式
    • /source-charset
    • /execution-charset

    我理解一下,就是:

    • 源文件里面的二进制,是根据源文件本身的编码格式来存的。
    • 比如\x45\xAB 这两个字节存在源码文件的某个位置上,然后根据source-charset的那种编码格式进行映射,把 \x45\xAB(文件中的存储的字节) <===> 字符 a ,
    • 然后,根据execution-charset的那种编码方式进行映射,字符 a <===> 某几个字节(内存中的存储的字节) ,因为最终你这个字符串要保存到内存中,所以现在就确定下来内存中这个字符串到底存储的哪几个字节。

    不知道我上面的流程理解对不对?(我觉得流程理解清楚,这个问题也就好解决了)

    而且想再问一下,解决“常量中有换行符”的最佳方案:

    • 正常情况只有一个人写代码的话,应该让这三个因素保持为 什么?
    • 现在我集成别人的 c++代码,他的文件编码格式全是 gb2312 (里面还有中文字符串常量),弄得我有点难搞。
    第 1 条附言  ·  2021-11-27 14:18:26 +08:00
    所以,为了让源文件在 Windows 的 vs 上编译 和 linux 上编译,源文件格式到底该用 utf-8 还是 utf-8-withBom 呢?😂
    28 条回复    2021-11-30 09:27:30 +08:00
    vinmkzr
        1
    vinmkzr  
       2021-11-27 11:33:37 +08:00
    我对 C 比较熟悉,你对字符组的理解按 C 来说是正确的;
    在 linux 上写代码用 gcc 编译的话,三个字符组默认都是 utf-8 ;
    我碰到过最差的情况是,项目里面有 EUC-JP ,shif-jis 几种日文编码混合,最后的解决办法是用 uchardet+iconv 写脚本全转换到 utf-8
    vanton
        2
    vanton  
       2021-11-27 11:43:07 +08:00
    系统改成 utf-8, 整个项目也用 utf-8
    mangohaoming
        3
    mangohaoming  
       2021-11-27 11:52:30 +08:00
    vs 中包含中文的文件最好使用 utf-8-withBom 的编码格式
    amiwrong123
        4
    amiwrong123  
    OP
       2021-11-27 11:55:00 +08:00
    https://www.cnblogs.com/jiangxueqiao/p/7464408.html#!comments

    这篇文章里提到:
    vs 编译器判断源文件编码类型的步骤为:
    1. 若文件开始处有 BOM(EF BB BF),则判定为 UTF-8 编码;
    2. 若没有 BOM ,则试图从文件的前 8 个字节来判断文件是否像 UTF-16 编码,如果像,则就判断为 UTF-16 编码。
    3. 如果既没 BOM ,也不是 UTF-16 编码,则使用系统当前的代码页(简体中文操作系统为 CP936 )。

    我理解是这样的:
    如果没有设置 /source-charset ,那么会执行这三步,根据这三步来得到最终的 /source-charset 。
    如果已经设置了 /source-charset ,那么不会执行这三个步骤,直接使用 设置的 /source-charset 。

    有没有经常用 vs 的老哥,是不是这样呀😂
    amiwrong123
        5
    amiwrong123  
    OP
       2021-11-27 11:59:25 +08:00
    @mangohaoming #3
    老哥你看看我 4 楼的问题呗

    这篇文章也是说,最好 utf-8-withBom 。但我的 c++代码也需要在 linux 上编译,就得跨平台。

    而且这篇文章说,最好使用 wchar_t 。我有点不理解。关键这个类型大家感觉也不常用啊,到时候和别人代码一对接,好多地方要改,还可能出错。。
    koebehshian
        6
    koebehshian  
       2021-11-27 13:03:29 +08:00   ❤️ 1
    源代码中不要有中文,字符串这种 UI 的东西放到配置文件中,配置文件统一用 utf8
    yolee599
        7
    yolee599  
       2021-11-27 13:21:08 +08:00 via Android
    源码请统一使用 utf-8 编码,不要贪图一时方便使用 gb2312 ,后面你会遇到各种各样问题
    wudicgi
        8
    wudicgi  
       2021-11-27 13:28:45 +08:00
    MSVC 的话,编译器的命令行参数中,手动加一项 /utf-8
    https://docs.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170

    我是倾向于直接加编译参数,而不是所有文件加上 BOM 头
    mangohaoming
        9
    mangohaoming  
       2021-11-27 13:40:49 +08:00
    @amiwrong123 linux 编译 utf-8-withBom 会存在问题吗,我印象中没碰到什么奇怪问题。我用 mingw 编译是 ok 的,我 vscode 的默认编码一直是 utf-8-withBom 的编码。
    amiwrong123
        10
    amiwrong123  
    OP
       2021-11-27 13:41:54 +08:00
    @koebehshian #6
    他的代码 是 那种处理中文文本的一种程序(类似,NLU )。总之,肯定会有 中文字符串常量。这没法阿
    amiwrong123
        11
    amiwrong123  
    OP
       2021-11-27 13:47:50 +08:00
    @yolee599 #7
    那要不要 withBom 呢?
    因为 vs 编译,最好是 withBom 的
    koebehshian
        12
    koebehshian  
       2021-11-27 13:59:06 +08:00
    @amiwrong123 他做 NLU 的,居然对中文编码都不了解
    skinny
        13
    skinny  
       2021-11-27 14:00:55 +08:00
    我虽然没有遇到过,但是千万别用 UTF8 with BOM ,坑太多了,之前写 PowerShell 脚本,5.1 及以下版本以 UTF8 编码输出的文本就是带 BOM 的,遇到二进制处理或传给别的外部命令处理时就容易出错,上次也是查了好一会儿才发现问题。
    amiwrong123
        14
    amiwrong123  
    OP
       2021-11-27 14:08:44 +08:00
    @wudicgi #8
    我也这么觉得。老哥你看看我 4 楼的问题呢,那篇文章把我弄懵了,我理解:
    如果已经设置了 /source-charset ,那么不会执行那三个步骤,直接使用 设置的 /source-charset 。对吗😂
    amiwrong123
        15
    amiwrong123  
    OP
       2021-11-27 14:13:31 +08:00
    @mangohaoming #9
    是吗,我就是怕 withBom 的 有问题,所以才来发帖😂
    amiwrong123
        16
    amiwrong123  
    OP
       2021-11-27 14:16:00 +08:00
    @koebehshian #12
    哎,我也不知道为啥他的源文件编码格式都是 gb2312😂
    我只是负责集成包装成接口给上层使用,而且之前他好像还说过,不要改他的源文件的编码格式,不然可能会出问题😂
    mangohaoming
        17
    mangohaoming  
       2021-11-27 14:27:16 +08:00
    @amiwrong123 看这个讨论,至少 gcc 是正常支持带 bom 的 https://www.v2ex.com/t/403068
    wudicgi
        18
    wudicgi  
       2021-11-27 15:19:20 +08:00
    @amiwrong123 那篇文章我觉得没啥参考价值,实际上不用搞这么复杂

    实践中,项目设为 Unicode 字符集这是毫无疑问的
    为了兼容性我会 #include <tchar.h>, 然后用 TCHAR 和 _tprintf() 之类符号代替 char/wchar_t, printf()
    同时也还是为了兼容性,我不会用 BOM 头,而是把源文件的字符集统一成 UTF-8, 加编译参数直接指定

    我之前在 V2EX 上发过的这个项目就是这么做的
    https://github.com/wudicgi/SpleeterMsvcExe
    wudicgi
        19
    wudicgi  
       2021-11-27 15:29:57 +08:00
    @amiwrong123 或者你在 VS 中为他的那些文件设置自己的 /source-charset 和 /execution-charset 参数

    /utf-8 等价于 /source-charset:utf-8 /execution-charset:utf-8
    可以给他的那些源文件加上 /source-charset:gb2312 编译参数

    但说实话,这样处理除了不用动他的那些文件外,和提前把那些文件都转为 UTF-8 编码没什么区别
    ipwx
        20
    ipwx  
       2021-11-27 16:20:09 +08:00
    utf-8 编码是截断安全的,它保证了多字节序列不可能出现换行符作为某个中文的一部分。

    gb2312 不是截断安全的。

    所以要用 utf-8
    nightwitch
        21
    nightwitch  
       2021-11-27 16:41:08 +08:00
    全部用 utf-8 with bom,msvc 开 /utf-8 的标志。
    远离 wchar 那一坨
    ipwx
        22
    ipwx  
       2021-11-27 16:53:30 +08:00
    所以其实 Qt 的标准解决方案挺香。源代码都是英文,但用 tr(...) 函数包起来。这个函数负责在运行时根据语言包资源文件查表。。。这样就可以做到源代码没有多字节字符了,哪里都不会出问题。
    ipwx
        23
    ipwx  
       2021-11-27 16:53:53 +08:00
    另外 QString 内存中是 UTF-16 。。。总之就挺香。
    lonewolfakela
        24
    lonewolfakela  
       2021-11-27 17:26:40 +08:00
    vs 的话,给编译器加 /utf-8 参数,然后所有源文件用 utf8 without bom 存,再在项目根目录加一个.editorconfig 文件,里面写上

    [*.{c,cpp,cc,cxx,h,hpp,ixx}]
    charset = utf-8

    这样比较好。
    3dwelcome
        25
    3dwelcome  
       2021-11-27 18:07:02 +08:00
    我也遇到楼主这种中文编码问题,只在某些特定平台,特定版本 clang 编译出问题。

    gcc 和 vc 倒是一点问题都没有。

    最后也没找到很直接的解决办法,写了一个源代码预处理工具,实时转换 utf8 编码。
    ysc3839
        26
    ysc3839  
       2021-11-27 18:34:27 +08:00 via Android
    我个人目前是编译参数加上 /utf-8 ,然后源代码全都用 UTF-8 without BOM 存,同时在 manifest 里面声明 active codepage 为 UTF-8 ( https://docs.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page ),代码中优先使用 UTF-16 。

    @ipwx Qt 的那个字符串我感觉有点尴尬,默认情况下它是 UTF-8 的字符串字面量,运行时要分配新内存解码为 UTF-16 ,如果想直接存成静态 UTF-16 ,需要包个宏,很影响代码观感。
    whi147
        27
    whi147  
       2021-11-28 10:47:25 +08:00 via iPhone
    我的操作是包一层翻译器,从外部读取字符串。代码内部都是同一编码
    macha
        28
    macha  
       2021-11-30 09:27:30 +08:00
    @amiwrong123 因为他在源码里面写了中文字符,我这边都强制大家写英文注释。vs 对中文支持不太好。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1006 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:28 · PVG 03:28 · LAX 12:28 · JFK 15:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.