Managing global vars between files

K

Kleenex

Reason: I am working on an embedded project which has very limited
memory (under 512 bytes, 60 or so of which is stack space), which
translates into limited stack space. In order to save on stack space, I
tried to only use parameters and stack space for things which are truely
temporary. Instead of passing a pointer to a data structure which should
always be populated with data, I have the data structure declared as a
global variable and all functions access it directly. This works fine
until I try and organize the code into seperate files.

Problem: I know I can declare a global var in 1 file, and declare it
with export in another so I can use that same global var across files,
but this leads to every file, except the main source file, having a nice
long list of exported vars at the beginning. Is there a better way to
make global vars in C, outside of declaring in 1 file, and exporting in
every other file that uses the variable?
 
B

Ben Pfaff

Kleenex said:
Problem: I know I can declare a global var in 1 file, and declare it
with export in another so I can use that same global var across files,
but this leads to every file, except the main source file, having a
nice long list of exported vars at the beginning. Is there a better
way to make global vars in C, outside of declaring in 1 file, and
exporting in every other file that uses the variable?

C doesn't have anything called "export". It has "extern",
though.

The usual way to use global variables is to declare them once,
with "extern", in a header file, e.g.

foo.h:

extern int foo;
extern double bar[];
extern void (*x) (double, int, ...);

Then each file that uses the globals includes the header:

#include "foo.h"

Exactly one .c file should actually define the global variables,
optionally with initializers:

int foo = 20;
double bar[] = {1, 2, 3, 42, 67, 128};
void (*x) (double, int, ...);
 
M

Mark A. Odell

Reason: I am working on an embedded project which has very limited
memory (under 512 bytes, 60 or so of which is stack space), which
translates into limited stack space. In order to save on stack space, I
tried to only use parameters and stack space for things which are truely
temporary. Instead of passing a pointer to a data structure which should
always be populated with data, I have the data structure declared as a
global variable and all functions access it directly. This works fine
until I try and organize the code into seperate files.

I've used smaller parts (128B) without globals but that's not the point
here, I admit.
Problem: I know I can declare a global var in 1 file, and declare it
with export in another so I can use that same global var across files,
but this leads to every file, except the main source file, having a nice
long list of exported vars at the beginning. Is there a better way to
make global vars in C, outside of declaring in 1 file, and exporting in
every other file that uses the variable?

If you have a "database" of global'ish data then put them all in a struct.
Then put the struct declaration and an extern of the struct object in a
file, like db.h, and include it from all files that require the
"database".
 
D

Dan Pop

In said:
Problem: I know I can declare a global var in 1 file, and declare it
with export in another so I can use that same global var across files,
but this leads to every file, except the main source file, having a nice
long list of exported vars at the beginning. Is there a better way to
make global vars in C, outside of declaring in 1 file, and exporting in
every other file that uses the variable?

You have just discovered one of the main reasons for using header files.
Put all the extern *declarations* in a header file that is included by
all the other source files. Put the corresponding *definitions* only in
one source file (not all of them need to be in the same source file, but
none of them should be in more than one source file).

This way, adding or removing one global only requires changes in two
files, which is a lot more manageable than changing all the source files
of the application.

Dan
 
P

Paul Hirose

I've written some C programs with many global variables shared by
several source files. My solution was something like this:


/* File globals.h
Every file needing access to the global variables #includes this file.
Exactly one of those files must #define MAKE_DEFS before the #include.
That will trigger generation of definitions.
*/

/* set up the preprocessor */

#ifdef MAKE_DEFS /* generate definitions */

#define GLOBAL /* expand GLOBAL to nothing */
#define EQUALS(x) =x

#else /* generate declarations only */

#define GLOBAL extern
#define EQUALS(x) /* expand initializer macro to nothing */

#endif


/* then create a couple global variables, one with an initializer */
GLOBAL int a;
GLOBAL int b EQUALS(2);

/* end of file */


If #define MAKE_DEFS has been seen, the preprocessor converts those
two lines to:
int a;
int b = 2;

Otherwise, they become:
extern int a;
extern int b;

To save myself the trouble of remembering where the definitions were
generated, I used a file named globals.c for that purpose. It had
just 2 lines:

#define MAKE_DEFS
#include "globals.h"


It's been many years since I used that technique (the code is on 5.25"
floppies, that's how long ago) and I'm writing this off the top of my
head, but that's basically how it was done. The idea isn't mine, by
the way. I got it from a book.
 
E

E. Robert Tisdale

Kleenex said:
Reason: I am working on an embedded project which has very limited
memory (under 512 bytes, 60 or so of which is stack space), which
translates into limited stack space. In order to save on stack space, I
tried to only use parameters and stack space for things which are truely
temporary. Instead of passing a pointer to a data structure which should
always be populated with data, I have the data structure declared as a
global variable and all functions access it directly. This works fine
until I try and organize the code into seperate files.

Problem: I know I can declare a global var in 1 file, and declare it
with export in another so I can use that same global var across files,
but this leads to every file, except the main source file, having a nice
long list of exported vars at the beginning. Is there a better way to
make global vars in C, outside of declaring in 1 file, and exporting in
every other file that uses the variable?

You're nuts.

You won't save any space by using global variables
and you will make your code virtually impossible to maintain.
You need to re-think your designs and eliminate global variables.
 
K

Keith Thompson

E. Robert Tisdale said:
You're nuts.

You won't save any space by using global variables
and you will make your code virtually impossible to maintain.
You need to re-think your designs and eliminate global variables.

Really? Local variables are likely to be allocated on the stack, of
which the system only has 60 bytes; global variables are likely to be
allocated in non-stack memory, of which there's about 450 bytes. It
seems plausible that using global rather than local variables makes
sense in these unusual circumstances.
 
D

Dan Pop

In said:
Really? Local variables are likely to be allocated on the stack, of
which the system only has 60 bytes; global variables are likely to be
allocated in non-stack memory, of which there's about 450 bytes. It
seems plausible that using global rather than local variables makes
sense in these unusual circumstances.

Furthermore, if used properly, global variables don't have a negative
impact on the code readability/maintenability.

For the small bits of local data needed by most functions (loop counters,
temporary variables and so on) static allocation can be used instead of
automatic allocation. Embedded control applications running on platforms
with this kind of resources seldom use recursive functions...

Dan
 
M

Malcolm

Keith Thompson said:
Really? Local variables are likely to be allocated on the stack, of
which the system only has 60 bytes; global variables are likely to be
allocated in non-stack memory, of which there's about 450 bytes. It
seems plausible that using global rather than local variables makes
sense in these unusual circumstances.
Exactly. The normal rule is that globals are a Bad Thing, but there are
always exceptions.
What you probably want to do is to declare a few variables g_temp1, g_temp2
etc, with the understanding that their value may be corrupted by a
subroutine. Leaf routines can use these variables at will, non-leaf if they
do so carefully. That way your precious memory space is reused.
 
T

Tim Rentsch

Paul Hirose said:
I've written some C programs with many global variables shared by
several source files. My solution was something like this:


/* File globals.h
Every file needing access to the global variables #includes this file.
Exactly one of those files must #define MAKE_DEFS before the #include.
That will trigger generation of definitions.
*/

/* set up the preprocessor */

#ifdef MAKE_DEFS /* generate definitions */

#define GLOBAL /* expand GLOBAL to nothing */
#define EQUALS(x) =x

#else /* generate declarations only */

#define GLOBAL extern
#define EQUALS(x) /* expand initializer macro to nothing */

#endif


/* then create a couple global variables, one with an initializer */
GLOBAL int a;
GLOBAL int b EQUALS(2);

/* end of file */

[...Then different #include's will get either declarations or ]
[ definitions depending on whether MAKE_DEFS is defined ]


Clearly there are benefits to having declarations and definitions
automatically synchronized, as is accomplished by this approach.

Using the C preprocessor to effect this synchronization has some
difficulties. It doesn't read very nicely for initializing arrays
or struct's, for example. Also, a common pattern is to declare
an array

extern SomeType some_array[];

whereas the definition might read

SomeType some_array[ MAXIMUM_ELEMENTS ];

which isn't accommodated by using GLOBAL and EQUALS.

A different approach, fairly simple to implement, is to find and
textually process global variable definitions, producing a header
file with declarations that may be #include'd. For example,

int a, b = 2;

unsigned long masks[5] = {
0x55555555,
0x33333333,
0x0f0f0f0f,
0x00ff00ff,
0x0000ffff,
};

would produce the declarations

extern int a, b;

extern unsigned long masks[];

in the resulting declaration header. I wrote such a tool for a
lightweight development environment and now use it routinely in any C
development work. It's surprisingly liberating.

Anticipating the next question - yes, the DE also automatically
generates and incorporates function prototypes along with variable
declarations. That has turned out to be amazingly beneficial. My
normal development mode now is compiler flag settings that require
prototypes for ALL functions, and duplicate prototypes not allowed.
No extra work to make that happen - just edit source files as usual,
and all the necessary generation gets done automatically. It's hard
to imagine going back now to doing that stuff by hand.
 
K

Kleenex

I wanted to thank everyone for their replies, even Tisdale (who I hope
has a fake email address). I have implemented my own version of the
header suggestions, and it appears to be working well.

Thanks again.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top