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 programs 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With