本文介绍了功能优化,在无限循环“的gcc -O2”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文

我被我的一个朋友提出以下谜:

Context
I was asked the following puzzle by one of my friends:

void fn(void)
{
  /* write something after this comment so that the program output is 10 */
  /* write something before this comment */
}

int main()
{
  int i = 5;
  fn();
  printf("%d\n", i);
  return 0;
}

我知道可以有多种解决方案,涉及的一些宏观和一些假设一些有关的执行和违反℃。

I know there can be multiple solutions, some involving macro and some assuming something about the implementation and violating C.

一个特别的解决方案,我感兴趣的是使有关堆栈的某些假设和写入以下code:(我的理解是不确定的行为,但可能工作为预期的许多实现)

One particular solution I was interested in is to make certain assumptions about stack and write following code: (I understand it is undefined behavior, but may work as expected on many implementations)

void fn(void)
{
  /* write something after this comment so that the program output is 10 */
  int a[1] = {0};
  int j = 0;
  while(a[j] != 5) ++j;  /* Search stack until you find 5 */
  a[j] = 10;             /* Overwrite it with 10 */
  /* write something before this comment */
}

问题

这项计划曾在MSVC罚款和GCC没有优化。但是,当我与的gcc -O2 标志编译它,或者试图在,其中 GCC 需要与未定义行为的循环,它以优化

This is undefined behavior so the compiler can really do anything at all, we can find a similar example in GCC pre-4.8 Breaks Broken SPEC 2006 Benchmarks, where gcc takes a loop with undefined behavior and optimizes it to:

L2:
    jmp .L2

文章说(的重点煤矿的):

当然,这是一个无限循环。由于SATD()无条件地
  执行未定义行为(这是一个3型功能),任何
  翻译(或没有)是一个完全可以接受的行为
  正确的C编译器
即可。未定义行为正在访问D [16]刚
  之前退出循环。在C99的是合法的创建一个指针
  一个元件的一个位置过去的数组的末尾,但该指针
  不得解除引用
。类似地,阵列单元的一个元素过去
  数组的末端必须不能被访问。

而如果我们检查与我们看到:

which if we examine your program with godbolt we see:

fn:
.L2:
    jmp .L2

的逻辑正在使用的优化可能是这样的:

The logic being used by the optimizer probably goes something like this:


  • 所有的元素 A 初始化为零

  • A 前或内环路,从不修改

  • 所以 A [J] = 5 始终是真实的! - >无限循环

  • 因为无限的,在 A [J] = 10; 无法访问,这样就可以优化掉,这样可以 A Ĵ,因为他们不再需要来确定循环状态。

  • All the elements of a are initialized to zero
  • a is never modified before or within the loop
  • So a[j] != 5 is always true -> infinite loop
  • Because of the infinite, the a[j] = 10; is unreachable and so that can be optimized away, so can a and j since they are no longer needed to determine the loop condition.
int d[16];

分析以下循环:

for (dd=d[k=0]; k<16; dd=d[++k])

是这样的:

在看见D [++ k]的,被允许假定递增值
  k的是阵列范围之内,否则未定义的行为
  发生。对于code在这里,GCC​​可以推断,k是范围0..15。
  过了一会儿,GCC时看到K&LT; 16,就对自己说:这AHA-
  前pression始终是真实的,所以我们有一个无限循环。

也许一个有趣的支点,是一个无限循环是否被认为是观察到的行为( w.r.t。到AS-if规则的)或没有,这是否影响一个无限循环,也可以优化掉。我们可以从的C11之前有至少有一些余地间pretation看到:

Perhaps an interesting secondary point, is whether an infinite loop is considered observable behavior(w.r.t. to the as-if rule) or not, which effects whether an infinite loop can also be optimized away. We can see from C Compilers Disprove Fermat’s Last Theorem that before C11 there was at least some room for interpretation:

许多知识渊博的人(包括我)阅读的话说,
  程序的终止行为不能被改变。显然,一些
  编译器作者不同意,否则不认为它很重要。该
  事实是合理的人持反对意见的跨pretation似乎
  以表明C标准是有缺陷的。

C11 的补充说明第 6.8.5 迭代语句和覆盖更详细的的。

C11 adds clarification to section 6.8.5 Iteration statements and is covered in more detail in this answer.

这篇关于功能优化,在无限循环“的gcc -O2”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 01:04