Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force GCC not to optimize away an unused variable?

One of the namespaces in my program is spread between two files. One provides the "engine", the other uses the "engine" to perform various commands. All of the initializations are performed on the "engine" side, including caching parameters fetched from setup library.

So, there's engine.cpp with:

    #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);
        }
    }

The variable happens never to be used again in engine.cpp but it's extensively used in commands.cpp.

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

    namespace MyNS
    {
       extern unsigned char variable;

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

After compiling and linking, I'm getting:

Init: var = 5
Command: var = 1

Now, if I uncomment the printf() in handler() I'm getting:

Engine: var = 5
Command: var = 5
Handler: var = 5

What would be the "correct" way to force GCC not to optimize it away in such a way that accessing it through extern from the other file would fetch the right value? Preferably without reducing the -O level for the rest of the application?

(for completeness case, main.h and ns.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();
    }

This minimized testcase doesn't exhibit this particular behavior; it seems one needs this situation to occur in much more complex environment to happen...

like image 832
SF. Avatar asked Nov 10 '22 23:11

SF.


1 Answers

eh... the solution was quite trivial.

I exchanged places of the declaration and definition of the variable.

engine.cpp:

extern unsigned char variable;

command.cpp:

unsigned char variable = 0;

That way the compiler has no doubts about need for this variable's existence while compiling commands and in engine it has to reach to the existing instance, it can't just create a temporary one on the spot.


EDIT: Now I've discovered another peculiarity. The value changes depending on where it's written to. The section of code in question is:

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;

The variable occurs near a place where several arrays are initialized with memset. The variable in question is PR_SOTU (the uppercase is inherited from when it was still a macro, and since it acts along with several other macros acting in a very similar context, it's likely to stay that way).

If move the assignment from its line 7 and place it after lines 1, 2 or 3, it receives the correct value 5. Placed after line 4 it gets the value 18. Anything below, and the value is 1. I moved definition of the variable to a different place (it was the last on the list of all namespace-globals, now it's first) to exclude possibility something writes at that specific memory location, but the behavior remains.

like image 67
SF. Avatar answered Nov 14 '22 21:11

SF.