Best use of a global struct variable in C

13,901

Solution 1

Choose more abstraction. If you can change the arguments to myFunc, then make its signature:

int myFunc(t_myStruct *arg)
{
    arg->myvar1 = ...

Now the function itself doesn't depend on the existence of a global variable at all. And the same for any other functions that need to operate on a struct of this type. If you must use a global variable then isolate the use of it as much as possible, i.e. use the global in as few places as possible.

If you can't change the function signature, I would choose the option from your question that is the most direct: the first. Just operate directly on the global variable.

Solution 2

Of the three options you listed, IMO, the first one is the best. Just carefully use the global structure.

The first and second options are almost identical, but whenever you start using pointers unnecessarily things get obfuscated and people tend to make more mistakes.

The third option is just a bad idea. Now you expect every function to be sure to write back the data when they're done? What if function A() and function B() are both making edits to the global structure? A() puts back the data when it's done, then B() finishes second and overwrites A()'s data? Now you need additional protection mechanisms in place... just a bad idea.

Solution 3

First of all why is it so unavoidable? Secondly why are those your only three options?

If you must access a global, your first option is not unreasonable - its already global, how much worse can it get?

Your second option is entirely pointless.

Your third option also has little merit, and the memcpy is unnecessary, you can assign a struct directly:

myGlobalData = localStruct ;

None of the solutions are advisable in a multi-threaded application.

So the answer is neither of the above. Instead, if there is no real reason for not doing so, qualify the global as static so that it is invisible outside the module in which it is defined, then in that same module define appropriate access functions.

Even without the static declaration, the access functions are a good approach since you can validate arguments, ensure data consistency, apply mutual-exclusion if necessary and during debugging you can trap all accesses by setting break-points only in the access functions rather the everywhere access might otherwise occur.

You should perhaps read A Pox on Globals - it refers to embedded systems, but is no less applicable to desktop applications.

Share:
13,901
Kyrol
Author by

Kyrol

Computer Science - University of Pisa C and Network engineer at qxip

Updated on June 04, 2022

Comments

  • Kyrol
    Kyrol almost 2 years

    I have a global var struct:

    typedef struct {
        int myvar1;
        int myvar2;
        int myvar3;
        ...
        int myvar10;
    } t_myStruct myGlobalData;
    

    I cannot avoid this global structures, so I have to use it. I have three options to use it:

    • Use the global var "as is" into any function. I.e.:

      int myFunc(void) {
          myGlobalData.myvar1 = ...
          myGlobalData.myvar10 = myGlobalData.myvar5 + ...
      }
      
    • Declare a local pointer and use it:

      int myFunc(void) {
          t_myStruct * p;
      
          p = &myGlobalData;
          p->myvar1 = ...
          ...
          p->myvar10 = p->myvar5 + ...
      }
      
    • Use local var and then copy to global struct:

      int myFunc(void) {
          t_myStruct localStruct;
      
          localStruct.myvar1 = ...
          localStruct.myvar10 = localStruct.myvar5 + ...
          myGlobalData = localStruct ;
      }
      

    Could explain me what is best way in general and why?

  • Kyrol
    Kyrol over 11 years
    Thanks! Just to know: you suggest me to use global var only when is strictly necessary ?
  • pb2q
    pb2q over 11 years
    @Kyrol yes that's right, and when you use a global, limit its use as much as possible
  • John Bode
    John Bode over 11 years
    @Kyrol: as this example shows, global variables can make code hard to re-use (if myFunc refers to globalData directly, then it can't be used as part of a different program that doesn't define globalData). Ideally, functions and their callers should communicate exclusively through arguments, return values, and exceptions (if applicable); they should not share state through globals. This makes it easier to re-use the function in another program.
  • Kyrol
    Kyrol over 11 years
    So, you suggest me that if I need to use a global data structure, I have to declare it static? I mean that in my case I need to have a global struct. Now I read what you linked me.
  • Clifford
    Clifford over 11 years
    @Kyrol: Well if it has static linkage, it is not truly global - so long as the only functions declared in the same translation unit are access functions and all other functions are in separate translation units to the global. The point is to use separate compilation to encapsulate and limit the visibility of the variable.