gcc 为什么在现代C++编译器中三字母会产生错误?

gmxoilav  于 2022-11-13  发布在  其他
关注(0)|答案(4)|浏览(221)

即使在GCC编译器中,如果不显式指定三字母属性,三字母也不会被编译。

#include<stdio.h>

int main()
 {
 int a=4;
 if((a==4) ??! (a==5))
   printf("\nHello world!");
 return 0;
 }

这个保存为try.c的程序只有在我们指定gcc -Wall -trigraphs try.c时才能在GCC编译器中编译,而且它仍然显示警告。你能找到一些编译器来处理三字母而不显示任何错误或警告吗?

7bsow1i6

7bsow1i61#

三字母是由1989年ANSI C标准引入的,并且保留在所有后来的C标准中(到目前为止;它们也出现在1998年发布的第一个ISO C标准中,以及所有后来的C标准中,直到C14。(三合字母在C17中被删除。感谢Jonathan Leffler和dyp追踪细节。)
引用C17标准的草案:
对原始特征的影响:使用三字母的有效C
2014代码可能是无效的,或者在本国际标准中可能具有不同的语义。如果三字母出现在原始字符串文字之外,作为实现定义的从物理源文件字符到基本源字符集的Map的一部分,实现可以选择转换C++ 2014中指定的三字母。
在C++17之前的语言中,它们不是可选的特性;所有符合的编译器 * 必须 * 支持它们,并按照各自语言标准的规定解释它们。
例如,如果此程序:

#include <stdio.h>
int main(void) {
    if ('|' == '??!') {
        puts("ok");
    }
    else {
        puts("oops");
    }
    return 0;
}

打印oops,则您的编译器不符合。
但是很多,也许是大多数,C编译器在默认情况下并不是完全符合标准的。只要编译器能够以某种方式符合标准,就足以满足标准的要求。(gcc需要-pedantic-std=...来做到这一点。)
但是,即使编译器完全符合标准,标准中也没有禁止编译器发出任何警告。符合标准的C编译器必须诊断任何违反语法规则或约束的情况,但它可以发出任意多的附加警告--而且它不需要区分所需的诊断和其他警告。
三字母很少被使用,绝大多数的开发系统都直接支持三字母所替代的所有字符:第一个月第三个月
事实上,三合字的使用很可能是“意外”的,而不是正确的:

fprintf(stderr, "What just happened here??!\n");

关于可能改变程序含义的三合字的警告(相对于语言没有三合字时的含义)是ISO标准允许的,恕我直言,这是完全合理的。大多数编译器可能都有关闭这种警告的选项。
相反,对于一个 * 不 * 实现三字母的C17编译器,警告那些在C14或更早版本中被视为三字母的序列是合理的,并且/或者提供一个支持三字母的选项。同样,一个禁用这样的警告的选项也是一件好事。

xbp102n0

xbp102n02#

GCC不支持三字母。您必须显式地启用它们:

gcc -trigraphs ...

GCC 4.7.1手册中指出:
-trigraphs
支持ISO C三合字。-ansi选项(以及用于严格ISO C一致性的-std选项)隐含-trigraphs
上面还说:
-Wtrigraphs
如果遇到任何可能改变程序含义的三合字,则发出警告(注解中的三合字不会发出警告)。此警告由-Wall启用。

mbzjlibv

mbzjlibv3#

默认情况下,它们可能处于关闭状态。
某些编译器支持关闭三字母识别得选项,或者在默认情况下禁用三字母识别并需要一个选项来打开它们
GCC might be one of the latter.ignore with warning虽然它在默认情况下应该是ignore with warning,但在这种情况下忽略可能会导致编译错误

wxclj1h5

wxclj1h54#

三字母在编译的早期就被转换了,甚至可以被替换成字符串文字。这使得三字母翻译产生的错误很难被检测到(如果你考虑使用日志调试,并且在源代码中找到输出,情况会更糟)。
你看到的警告将帮助你快速找到可能的罪魁祸首,追踪bug的来源。基本上,它是在警告你,有些东西可能并不像你想象的那样。

相关问题