【问题标题】:Force GCC not to optimize away an unused variable?强制 GCC 不优化未使用的变量?
【发布时间】:2014-12-23 21:08:56
【问题描述】:

我的程序中的一个命名空间分布在两个文件之间。一个提供“引擎”,另一个使用“引擎”执行各种命令。所有初始化都在“引擎”端执行,包括从设置库中获取的缓存参数。

所以,engine.cpp 有:

    #include <stdio.h>
    #include "ns.h"

    namespace MyNS
    {

        unsigned char variable = 0;

        void init()
        {
            variable = 5;
            printf("Init: var = %d\n",variable);
        }

        void handler()
        {
            // printf("Handler: var = %d\n",variable);
        }
    }

该变量碰巧再也不会在engine.cpp 中再次使用,但它在commands.cpp 中被广泛使用。

    #include <stdio.h>
    #include "ns.h"

    namespace MyNS
    {
       extern unsigned char variable;

      void command()
       {
          printf("Command: var = %d\n",variable);
       }
    }

编译和链接后,我得到:

初始化:var = 5
命令:var = 1

现在,如果我取消注释 handler() 中的 printf(),我会得到:

引擎:var = 5
命令:var = 5
处理程序:var = 5

什么是“正确”的方法来强制 GCC 不以这样的方式优化它,即通过 extern 从另一个文件访问它会获取正确的值?最好不要降低应用程序其余部分的-O 级别?

(为了完整性,main.hns.h: )

    #include "ns.h"

    int main(int argc, char** argv)
    {
        MyNS::init();
        MyNS::command();
        MyNS::handler();

        return 0;
    }

    namespace MyNS
    {
        void init();
        void command();
        void handler();
    }

这个最小化的测试用例没有表现出这种特殊的行为;似乎需要在更复杂的环境中发生这种情况......

【问题讨论】:

  • 我很难相信对具有外部链接的变量的赋值会被优化掉。你确定不是对init 的调用被优化掉了吗?
  • 我觉得这可能是静态初始化顺序问题?
  • 也许你想要volatile ....
  • 我不能用一个小例子来重现这个 - 编译器不应该像你声称的那样优化它。你能创建一个 complete 可编译的例子来展示这个吗?另外,您使用的是什么平台和 gcc 版本,使用了任何特定的编译器标志?任何其他不寻常的事情,例如多线程,动态加载的共享库,您的 command_x()/init() 函数实际上是从全局对象的构造函数等调用的吗?
  • 另外,我将尝试编写一个最小化的测试用例。以目前的形式,该程序太大而不能仅仅“裁剪一些行”。

标签: c++ gcc compiler-optimization


【解决方案1】:

嗯...解决方案很简单。

我交换了变量的声明和定义的地方。

engine.cpp

extern unsigned char variable;

command.cpp

unsigned char variable = 0;

这样编译器在编译commands 时不会怀疑此变量是否存在,而在engine 中它必须到达现有实例,它不能只是在现场创建一个临时实例。


编辑:现在我发现了另一个特点。该值根据写入的位置而变化。有问题的代码部分是:

1:   varso = SharedObject::Instance()->varso;
2:  memset(det_map,0,sizeof(det_map));
3:  memset(gr_map,0xFF,sizeof(gr_map));
4:  memset(gr_ped,false,sizeof(gr_ped));
5:  memset(&stan,0,sizeof(stan));

6:  stan.SOTUstage = 1;
7:  PR_SOTU = varso->NrPSOTU;

该变量出现在一个使用 memset 初始化多个数组的位置附近。有问题的变量是PR_SOTU(大写字母是从它还是一个宏时继承而来的,并且由于它与其他几个在非常相似的上下文中作用的宏一起作用,它很可能会保持这种状态)。

如果将赋值从第 7 行移到第 1、2 或 3 行之后,它会收到正确的值 5。放在第 4 行之后,它的值是 18。以下任何内容,值为1。我将变量的定义移到了不同​​的位置(它是所有命名空间全局变量列表中的最后一个,现在是第一个)以排除在该特定内存位置写入某些内容的可能性,但行为仍然存在。

【讨论】:

  • 无论如何都不应该允许编译器优化外部变量的使用。我怀疑发生了其他事情。
  • @bames53:查看我的编辑。这种行为真的很奇特。
  • 几乎可以肯定,您所看到的是未定义行为的结果。获取一些分析工具、静态分析器、valgrind、地址和内存清理器等,找出程序做错了什么。
  • 这听起来像是静态初始化命令的惨败。在出现错误行为的地方设置断点,我敢打赌,您会发现您所处的位置不能保证在您期望发生的初始化之前发生。
猜你喜欢
  • 2022-01-04
  • 1970-01-01
  • 2012-02-09
  • 2017-09-20
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多