tags:

views:

140

answers:

4

main file (prog.c):

#include "log.c"
#include "library.c"
static char * Foo;

If some variable (char * Foo) is defined in main file (prog.c), and it is required by log.c function called from library.c, how to correctly declare Foo to be visible from log.c's namespace?

+2  A: 

Add its declaration to some .h file that is included in both .c files. Define it in one of the files.

Of course, it can't be declared static for this to work since the static keyword is a promise that the name won't be needed outside of that particular module.

For example, in prog.h:

extern char *Foo;

in prog.c:

#include "prog.h"
#include "log.c"
#include "library.c"

char * Foo;         // make sure that Foo has a definition

// some code probably wants to make Foo have a value other than NULL

in log.c:

//... other includes
#include "prog.h"    // and now Foo is a known name

// some code here is using the global variable Foo

Now, for the bad news.

Doing this sort of thing creates a coupling between the prog.c and log.c modules. That coupling adds to the maintenance cost of your application as a whole. One reason is that there is no way to prevent other modules from using the global variable also. Worse, they might be using it completely by accident, because its name is insufficiently descriptive.

Worse, globals make it much more difficult to move from single-threaded programs to multi-threaded programs. Every global variable that might be accessed from more than one thread is a potential source of really hard to diagnose bugs. The cure is to guard information that must be global with synchronization objects, but overused that can result in an application where all the threads are blocked except the one that is currently using the global, making the multi-threaded application effectively single threaded.

There certainly are times when the inter-module coupling implied by global variables is acceptable. One use case is for general purpose application-wide options. For instance, if your application supports a --verbose option that makes it chatter while it works, then it makes sense for the flag that is set by the option and tested throughout the code would be a global variable.

There are certainly questions at SO that delve deeply into the pitfalls of globals and will provide guidance on their sensible use.

RBerteig
+1  A: 

You want extern. When you extern a variable name you're making a "promise" that the variable will exist when you link. You want to give it storage in a .c file but extern it in a header. That way it's just instantiated once, in the .c's object file. You don't want to have two different .o's using the same name to refer to different locations in memory. (As noted above it's nearly always bad form to require something like this for a library.)

So in a common header you'd have

common.h

extern Foo bar;

Then in prog.c

Foo bar;

And when you included common.h in log.c you could access bar from prog.c

Note that static is very different in C than in Java. In Java it's global to an Class and available for anyone, even without an instance of the class. In C static means that variable is not visible outside of the compilation unit.

Paul Rubel
+2  A: 

It is aconventional to include the library source code in your main program:

#include "log.c"
#include "library.c"
static char * Foo;

(The semi-colon is needed.)

However, given that is what you are doing, if "log.c" needs to see the declaration, you could simply do:

static char * Foo;
#include "log.c"
#include "library.c"

Now the static declaration is visible to "log.c" (and "library.c").

If you go for a more conventional setup, then you would have the code in "log.c" access a global variable declared in an appropriate header (rather than a file static variables). However, such dependencies (where a library file depends on a global variable) are a nuisance. The main program (or some piece of code) has to provide the variable definition. It would be better to have the code in "log.c" define the variable, and the (presumed) header "log.h" would declare the variable, and then the main program would set the variable accordingly. Or, better, the code in "log.c" would provide a function or several functions to manipulate the variable, and the header would declare those functions, and the main program would use them.

Jonathan Leffler
+1  A: 

The simple answer is:

static char * Foo;
#include "log.c"
#include "library.c"

Which makes Foo visible in log.c and library.c simply by virtue of the "declare before use" rule.

However what you really need to know is that this is nasty code! You have committed at least two sins; Use of global variables and failure to understand the use separate compilation and linking.

Clifford
Apologies to Jonathan Leffler who already gave that answer! I'll let it stand however.
Clifford