显然没有证件的GCC行为“常数” c

发布于 2025-02-06 12:36:09 字数 847 浏览 4 评论 0原文

考虑以下C代码:

#include <stdio.h>

int x = 5;
int y = x-x+10;
int z = x*0+5;
int main()
{
  printf("%d\n", y);
  printf("%d\n", z);
  return 0;
}

ANSI C90标准状态“具有静态存储持续时间[...]的对象的所有表达式均为恒定表达式”(6.5.7约束3)。

显然,Y和Z的初始化器不是恒定表达式。实际上,尝试使用clang main.cclang -ansi main.c给出了错误。

但是,使用gcc main.cgcc main.c -ansi -pedantic -wextra -wall -wall完全没有任何错误,然后运行10和5。

另一方面,尝试以下内容:

#include <stdio.h>

int x = 5;
int main()
{
  int y[x-x+2];
  printf("%lu\n", sizeof(y));
  return 0;
}

使用gcc -ansi -pedistic ...clang -ansi -petantic ...时,给出警告。

因此,GCC随机执行数学上正确的取消取消,以假装某物是一个恒定的表达式,即使不要求(-Ansi)。为什么这是?这是一个错误吗?

顺便说一句,我的GCC版本是9.4.0,而我的clang版本是10.0.0-4。

Consider the following C code:

#include <stdio.h>

int x = 5;
int y = x-x+10;
int z = x*0+5;
int main()
{
  printf("%d\n", y);
  printf("%d\n", z);
  return 0;
}

The ANSI C90 standard states "All the expressions for an object that has static storage duration [...] shall be constant expressions" (6.5.7 constraint 3).

Clearly the initializers for y and z are not constant expressions. And indeed, trying to compile the above C code with clang main.c or clang -ansi main.c gives an error for this reason.

However, compiling with gcc main.c or even gcc main.c -ansi -pedantic -Wextra -Wall gives no errors at all, and runs, printing 10 and 5.

On the other hand, trying something like the following:

#include <stdio.h>

int x = 5;
int main()
{
  int y[x-x+2];
  printf("%lu\n", sizeof(y));
  return 0;
}

gives a warning when compiled with gcc -ansi -pedantic ... or clang -ansi -pedantic ....

So gcc randomly performs the mathematically correct cancellations in order to pretend that something is a constant expression, even when asked not to (-ansi). Why is this? Is this a bug?

By the way, my gcc version is 9.4.0 and my clang version is 10.0.0-4.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

且行且努力 2025-02-13 12:36:09

没有看,就有一个简单的解释:检查初始化器是否是可接受的常数表达式的代码在之后的内部表示上运行, 可以简化算术,因此它永远不会“看到”您的> xxx*0

这可能使GCC中规则的实现更加简单:它只需要问“这个节点代表常数吗?”而不是“这棵树是我以后可以评估为常数的一棵树吗?”。它还促进了他们可能想要的以后标准的行为(请参见下文),-Ansi的特殊情况可能会增加不良量的代码复杂性。

是一个错误吗?可以说。但这是一个很小的影响,以至于不太可能被修复。它适用于有效代码正确,并且在“真正”无效的代码上正确错误,该代码实际上可能导致问题。它仅以相当无害的方式与标准偏离标准,并且仅针对C90(因为C99和后来的标准说“实施可以接受其他形式的恒定表达方式”,这使GCC纬度允许允许表达不在洗衣清单,只要它具有恒定价值)。

Without looking, there's one simple explanation: the code that checks whether the initializer is an acceptable constant expression operates on an internal representation after a pass that does arithmetic simplification, so it never "sees" your x-x or x*0.

This probably makes the implementation of the rule in GCC simpler: it just has to ask "is this node one that represents a constant?" rather than "is this tree one that I could evaluate as a constant later on?". It also facilitates the behavior that they probably want for the later standards (see below), and a special case for -ansi would probably add an undesirable amount of code complexity.

Is it a bug? Arguably. But it's one with such a small impact that it's not especially likely to get fixed. It works correctly for valid code, and it errors correctly on "really" invalid code that could actually cause a problem. It only deviates from the standard in a fairly harmless way, and only for C90 (since the C99 and later standards say "an implementation may accept other forms of constant expressions", which gives GCC latitude to allow an expression that mentions things not on the laundry list, as long as it has a constant value).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文