【问题标题】:Why GCC optimizes accessing global array variable为什么 GCC 优化访问全局数组变量
【发布时间】:2021-12-10 09:58:22
【问题描述】:

我的代码有问题,因为 gcc 的想法似乎与我的不同。 这是问题的简化版本。

struct foo
{
    uint16_t var;
};

struct foo foos[7];
struct foo foo;
uint16_t update_visual_alert(uint8_t match)
{
    for(uint8_t i; i < 4;i++)
    {
        uint16_t color = 5;
        if(match)
        {
            color = foos[i].var;
        }
        return color;
    }
    return 1;
}

用-01 GCC 正在切割

color = foos[i].var;

Failed

但它正在访问单个全局变量。

color = foo.var;

Working

显然,它不会在没有优化或使用 volatile 关键字的情况下被剪切,无论是在颜色还是结构数组上。 但是添加

printf("%d",&color);

强制 gcc 也访问它们。 为什么 gcc 会优化它?

这是我在应用程序中使用的算法的简化版本,它导致了我忽略值的错误。

【问题讨论】:

  • for(uint8_t i; i &lt; 4; = 访问未初始化的变量 = 任何事情都可能发生
  • 谢谢,看来这就是根本原因。如此专注于奇怪的行为,我没有注意到这样的错误。
  • @BullNuk 欢迎您。 gcc -Wall 其中包括 -Wuninitialized 是您的朋友,如果由于某种原因您无法编译时出现警告,您还有一个出色的工具:cppcheck --enable=all .(尽管名称为 cpp,它也适用于 C)
  • 如果您打算使用 Godbolt(这是个好主意),请在其分享按钮中包含实际的可分享链接。然后人们就可以实际试用代码并进行自己的微小更改,而仅凭屏幕截图是无法做到的。

标签: c gcc optimization


【解决方案1】:

gcc 只是阻止了 UB。始终使用 -Wall -Wextra 作为最低警告级别。使用这些选项 gcc 会生成警告:

<source>: In function 'update_visual_alert':
<source>:14:22: warning: 'i' is used uninitialized [-Wuninitialized]
   14 |     for(uint8_t i; i < 4;i++)
      |                    ~~^~~
Compiler returned: 0

没有 UB gcc 做你想做的事(使用-O3):

struct foo
{
    uint16_t var;
};

struct foo foos[7];
struct foo foo;
uint16_t update_visual_alert(uint8_t match)
{
    for(uint8_t i; i < 4;i++)
    {
        uint16_t color = 5;
        if(match)
        {
            color = foos[i].var;
        }
        return color;
    }
    return 1;
}

update_visual_alert:
        mov     eax, 5
        ret
uint16_t update_visual_alert1(uint8_t match) // no UB
{
    for(uint8_t i = 0; i < 4;i++)
    {
        uint16_t color = 5;
        if(match)
        {
            color = foos[i].var;
        }
        return color;
    }
    return 1;
}
update_visual_alert1:
        test    dil, dil
        mov     eax, 5
        cmovne  ax, WORD PTR foos[rip]
        ret
foo:

顺便说一句,您的循环根本没有意义,因为它总是采用数组第一个元素的值。也永远无法联系到return 1

【讨论】:

  • 实际上循环总是会返回数组第0个元素的值(如果match为真),因为return color;总是在第一次迭代时发生。
  • @NateEldredge 好地方 :)
  • 我知道这没有意义,为了便于阅读,我删除了所有内容:P。而且我剥离了太多,实际上将结果传递给另一个函数是无效的。但是,是的,我需要更频繁地坚持 -Wall。这是一个很容易被我忽略的错误。
猜你喜欢
  • 2017-09-20
  • 2016-01-25
  • 2012-02-26
  • 2011-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多