能否让GCC编译带BOM的UTF-8源文件?

13

我使用Microsoft Visual Studio在Windows和GCC在Ubuntu Linux上开发C++跨平台应用。

在Visual Studio中,我可以在我的代码中使用Unicode符号,例如"π"和"²"。Visual Studio总是将源文件保存为带有BOM(字节顺序标记)的UTF-8格式。

例如:

// A = π.r²
double π = 3.14;

GCC只有在我先删除BOM后才能愉快地编译这些文件。如果我不删除BOM,就会出现以下错误:
wwga_hydutils.cpp:28:9: error: stray ‘\317’ in program wwga_hydutils.cpp:28:9: error: stray ‘\200’ in program
这让我想到了一个问题:
有没有办法让GCC在不删除BOM的情况下编译UTF-8文件?

我正在使用:

和:


正如第一位评论者指出的那样,我的问题不是BOM,而是在字符串常量之外有非ASCII字符。 GCC不喜欢符号名称中的非ASCII字符,但事实证明GCC完全兼容UTF-8带BOM。

2
在我的gcc 4.4.5中,使用包含您问题中的UNICODE字符的字符串可以正常工作。带有BOM的文件。此外,您收到的错误与BOM无关,但似乎是问题中的UNICODE字符位于任何字符串之外(这就是为什么它们被称为_stray_)。 - Some programmer dude
@JoachimPileborg 是的,Unicode 字符位于字符串之外,“π” 是我用作符号名称的字符,“²” 只在注释中使用。当我删除字节顺序标记时,确实消除了控制台输出中的错误,但我想这并不保证 GCC 真正按照我的期望处理这些字符。 - Boinst
@JoachimPileborg,我已经更新了问题,包括我在使用Unicode字符的上下文。 - Boinst
1
在UTF-8流中存在BOM是一个错误,因为它会阻止将三个BOM连接在一起并得到正确的结果。 - tchrist
2
双精度 π = 3.14; - chqrlie
1
clang支持在标识符中使用这些符号,而gcc仅支持在字符串中使用。要在gcc中的标识符中使用Λ(希腊字母lambda),请使用通用字符名称(https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_74/rzarg/unicode_standard.htm),因此函数`funΛ()`将被写成`fun\u039B()`以在gcc中运行。我将编译器更改为clang,一切都正常了。gcc的`-finput-charset=UTF-8 -fextended-identifiers也没有帮助。-fextended-identifiers仅支持通用字符名称格式,如果关闭(-fno-extended-identifiers),即使是fun\u039B()`也会失败。 - Sahil Singh
2个回答

4

虽然GCC支持Unicode标识符,但不支持UTF-8输入。因此,Unicode标识符必须使用\uXXXX和\UXXXXXXXX转义码进行编码。然而,对C++预处理器进行简单的一行修补程序可以使GCC和g++处理UTF-8输入,前提是安装了支持C99转换的最新版本iconv。详细信息请参见GCC中的UTF-8标识符

然而,这个修补程序非常简单,可以直接在这里给出:

diff -cNr gcc-5.2.0/libcpp/charset.c gcc-5.2.0-ejo/libcpp/charset.c

输出:

*** gcc-5.2.0/libcpp/charset.c  Mon Jan  5 04:33:28 2015
--- gcc-5.2.0-ejo/libcpp/charset.c  Wed Aug 12 14:34:23 2015
***************
*** 1711,1717 ****
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;
--- 1711,1717 ----
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, "C99", input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;

即使有了补丁,仍需要两个命令行选项(-finput-charset-fextended-identifiers)来启用 UTF-8 输入。特别是,请尝试类似以下的内容
/usr/local/gcc-5.2/bin/gcc \
    -finput-charset=UTF-8 -fextended-identifiers \
    -o circle circle.c

4
根据GCC Wiki,目前还不支持此功能。您可以使用-fextended-identifiers并预处理代码将标识符转换为UCN。从链接的页面中获取:
perl -pe 'BEGIN { binmode STDIN, ":utf8"; } s/(.)/ord($1) < 128 ? $1 : sprintf("\\U%08x", ord($1))/ge;' 

另请参阅g++ unicode变量名C++11中的Unicode标识符和源代码


GCC在2020年中期追赶到版本10。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接