强制GCC不要优化掉未使用的变量?

SF.*_*SF. 5 c++ gcc compiler-optimization

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

所以,有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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

变量永远不会被再次使用,engine.cpp但它被广泛使用commands.cpp.

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

    namespace MyNS
    {
       extern unsigned char variable;

      void command()
       {
          printf("Command: var = %d\n",variable);
       }
    }
Run Code Online (Sandbox Code Playgroud)

编译和链接后,我得到:

Init:var = 5
命令:var = 1

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

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

什么是"正确"的方式迫使GCC不以这样的方式优化它以便extern从其他文件访问它将获取正确的值?优选地,不降低-O其余应用的水平?

(完整性案例,main.h和ns.h:)

    #include "ns.h"

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

        return 0;
    }
Run Code Online (Sandbox Code Playgroud)
    namespace MyNS
    {
        void init();
        void command();
        void handler();
    }
Run Code Online (Sandbox Code Playgroud)

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

SF.*_*SF. 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;
Run Code Online (Sandbox Code Playgroud)

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

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

  • 几乎可以肯定,您所看到的是未定义行为的结果。获取一些分析工具,静态分析器,valgrind,地址和内存清理器等,并找出程序做错了什么。 (4认同)
  • 无论如何,都不应该允许编译器优化 extern 变量的使用。我怀疑还有其他事情发生。 (2认同)
  • 这听起来像是静态初始化顺序的惨败。在出现错误行为的地方设置一个断点,我敢打赌,您会发现您所处的位置不能保证在您期望在初始化之前发生的情况发生。 (2认同)