【问题标题】:why optimization breaks this C code?为什么优化会破坏这个 C 代码?
【发布时间】:2012-10-08 03:24:20
【问题描述】:

有人知道为什么 -O2 会破坏这段代码吗?我怀疑这是 gcc 中的一个错误,因为它适用于不同的平台和不同版本的 gcc。但是,代码也可能包含一些我不知道的特殊性。谁能赐教?

这里是代码,它是一个可变数量的嵌套循环的实现,产生所有可能的组合。预期的输出是

100 1
010 2
001 4
110 3
101 5

以及损坏的版本报告

100 1
010 2
001 4
100 1
010 2

代码是:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main()
{
    int nmax = 5; // finish after 5 combinations
    int n = 3;    // three elements
    int *out = (int*) calloc(nmax, sizeof(int)); 
    int *cnt = (int*) calloc(n, sizeof(int)); // declaring volatile solves the problem. But why ?
    int il, nl, i = 0;
    for (nl=1; nl<=n; nl++)
    {
        for (il=0; il<nl; il++) cnt[il] = 0;
        cnt[nl-1] = -1;
        while ( cnt[0]<n-nl )
        {
            for (il=nl-1; il>=0; il--)
            {
                if ( ++cnt[il] < n-nl+il+1 ) break;
                cnt[il] = 0;
            }
            for (il=1; il<nl; il++)
            {
                if ( cnt[il] <= cnt[il-1] ) cnt[il] = cnt[il-1]+1;
            }
            for (il=0; il<nl; il++) out[i] |= 1<<cnt[il];
            if ( ++i >= nmax ) break;
        }
        if ( i >= nmax ) break;
    }
    for (i=0; i<nmax; i++)
    {
       for (il=0; il<n; il++) printf("%d", out[i]&(1<<il) ? 1 : 0);
       printf("\t%d\n", out[i]);
    }
    free(cnt);
    free(out);
    return 0;
 }

【问题讨论】:

  • 您使用的是哪个版本的 gcc?在 4.7.2(在 x86 上)使用 -O2 时工作正常
  • 您的代码中可能有一些未定义的行为。当我遇到这样的问题时,我会想到的最后一个想法是编译器错误。
  • 啊啊啊!为什么这些 i,l,1 看起来如此相似!我只是想读这个代码-sn-p :) :)
  • 好的。找出“why”的一种快速解决方案是 objdump -S 两个版本的代码(有和没有 volatile),然后区分两者。您将确切地了解 gcc 的想法,然后您可以从那里获取其余的信息...
  • @KirilKirov 这是程序的验证:pastebin.com/XNdZLEYV。在这种情况下很容易,因为程序是确定性的并且没有输入。如果您使用的是最新的 Debian 或 Ubuntu,您可以使用“apt-get install frama-c”获取静态分析器

标签: c optimization gcc volatile


【解决方案1】:

您应该发布您正在使用的 gcc 版本、目标以及您正在使用的确切命令行的详细信息。此外,发布由 GCC 生成的程序集(例如,通过使用 -S 选项)会有所帮助。

我猜编译器错误地将cnt[0] 提升到while 循环控制表达式之外。以下修改(将模拟提升)会产生错误的输出:

// ...

for (nl=1; nl<=n; nl++)
{
    int tmp;                            // <== new line
    for (il=0; il<nl; il++) cnt[il] = 0;
    cnt[nl-1] = -1;
    tmp = cnt[0];                       // <== new line
    while ( /*cnt[0] */ tmp <n-nl )     // modified
    {
        for (il=nl-1; il>=0; il--)

// ...

当然,这只是一个猜测 - 获取请求的详细信息以便检查生成的代码会更有趣。

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 2021-08-15
    • 1970-01-01
    • 2022-07-05
    • 2016-01-19
    • 2015-12-25
    • 2021-02-01
    • 2012-08-12
    • 2021-05-27
    相关资源
    最近更新 更多