开发者

Including C header file with lots of global variables

开发者 https://www.devze.com 2022-12-31 21:04 出处:网络
I have an include file with 100+ global variables. It\'s being used in a library, but some programs that I\'m linking the lib to also need to access the globals.

I have an include file with 100+ global variables. It's being used in a library, but some programs that I'm linking the lib to also need to access the globals.

The way it was built:

// In one library .c file
#define Extern

// In the progra开发者_Python百科ms that use the globals
#define Extern extern

// In the .h file
Extern int a,b,c;

I had a hard time understanding why the original programmer did that so I removed that define Extern stuff. Now I think I understand the thing about TU with the help of stackoverflow: 1, 2, 3.

Now I understand that I should define the global variables in one .c file in the library and use extern in the .h file. The problem is that I don't want to duplicate code.

Should I go back to that #define Extern voodoo?


The trick here is that the .h file is being used in two different ways - it's being used as a normal .h file where all the globals are declared extern and it's also being used to define the globals themselves (with no extern). This is an ugly hack but you can understand why someone felt it necessary if you have a large number of globals (a sure sign of very bad software design !).

Anyway, there is a somewhat more elegant solution - you can put all your globals in a single global struct, e.g.

//
// globals.h
//

typedef struct {
    int a;
    int b;
    // ...
    int z;
} Globals;

extern Globals globals; // declaration

-

//
// globals.c
//

#include "globals.h"

Globals globals; // definition

-

Then when you need to refer to a global it's e.g. globals.a instead of just a, which might seem like an inconvenience but this is arguably clearer and more manageable than just having naked globals scattered throughout the code.


It is a bad pattern to have to define Extern in every .c file. Removing it is probably best, but you need to replace this functionality somehow. One approach is that you could use a #define in the .c file that needs to define these globals. This define will signal to the .h to not extern the global variables.

For example: The one library .c file:

#define FOO_LIBRARY_C
#include "foo_library.h"

The other .c files:

#include "foo_library.h"

foo_library.h:

#ifdef FOO_LIBRARY_C
int a,b,c
#else
extern int a,b,c
#endif

or

#ifdef FOO_LIBRARY_C
#define GLOBAL_PREFIX
#else 
#define GLOBAL_PREFIX extern
#endif

GLOBAL_PREFIX int a,b,c

This reduces the need to define the same thing in every single source file (except one) and would help to reduce errors. I also wouldn't call it Extern as that can just cause confusion, as it may or may not be "extern"


Maybe I'm missing something too, but I ALWAYS use inclusion guards on all the header files I create:

foo.h:

#ifndef FOO_H
#define FOO_H

extern int foo;

#endif

foo.c:

#include "foo.h"

int foo = 0;

bar.c:

#include "foo.h"
#include <stdio.h>
int main(int argc, char** argv)
{
    printf("foo:%d\n",foo);
    return 0;
}


The macro stuff is silly for this. Just put

extern int myGlobal;

in your header file, and in ONE .c file (typically one with the same name as the .h file), put

int myGlobal;

No need to get stressed about this level of "duplication".


I might be missing something, but I see no difference between the #define thingy and just using the extern keyword.

Basically, you have to declare the vars in a .h file and define them in a .c file. Don't consider it code duplication - I think changing the point of view is the best thing you can do here :). You may write more lines of code, but they'll be readable :D.


In large programs it is very important to have a single line to declare and define a global variable. Therefore, the macro approach described above is the proper way to address the issue.

// globals.h 
#ifndef GLOBALS_H 
#define GLOBALS_H  
#ifndef EXTERN 
#define EXTERN extern 
#endif
EXTERN int i; 
#endif  

// globals.c 
#define EXTERN 
#include "globals.h" 


As a rule of thumb - don't use global variables. Sometimes you need to use static variables in file but it is best to try to avoid them at all:

  • You cannot unit test properly code which contains global variables
  • There is no clean separation between modules which can cause problems with isolation of errors
  • It is usually not thread safe. You have to wrap them with mutexes etc. if you want to use threads (tends to be better and better idea as we get more and more cores) you can run into troubles with writeable shared state.

Sometimes in C you cannot avoid them (especially in code inherited by someone) but best is to keep them out.

As for the declaration - it might be helpful in such case:

// globals.h

#ifndef GLOBALS_H
#define GLOBALS_H

#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN int i;
#endif

// globals.c
#define EXTERN
#include "globals.h"


While this can be annoying at first it does help you avoid having to type thing twice or forgetting to include something in a .c file at all. I've seen:

#define FOO_C_

#include "foo.h"
#include "bar.h"

int foo_doit(int a, int b, int c) {
...
}

with foo.h being:

#ifndef FOO_H_
#define FOO_H_

#ifdef FOO_C_
#define GLOBAL
#define DECLARE( type, name, value) type name = value
#else
#define GLOBAL extern
#define DECLARE( type, name, value) extern type name;
#endif

GLOBAL int foo_doit(int a, int b, int c);
GLOBAL int foo_it; // uninitialized global variable
DECLARE(char, that[], "that");

// and sometimes using:
#ifdef FOO_C_
char word[] = letters;
#else
extern char word[];
#endif


#endif // FOO_H_
0

精彩评论

暂无评论...
验证码 换一张
取 消