Previous Table of Contents Next


C-through Macros

The best way to declare share, export, and import variables is to define macros for the required C syntax. Figure 5.2 shows three suggested macro definitions and how to use them (along with rules for declaring local variables.) For variables you want visible throughout the file, use the SHARE macro before the file's first function definition to declare (and define) each variable. For example,

SHARE int x;

This statement expands to

static int x;

which gives x the desired visibility. Note that you never use SHARE inside a function because it would just define a local variable.

Figure 5.2 How to Declare C Variables and Functions "Visibility" Macros
#define SHARE static
#define EXPORT
#define IMPORT extern

Declaring Variables

Visibility Storage Where referenced Storage/visibility specifier(s)
Local Automatic In block Define at beginning of block with no specifier
Local Static In block Define as static at beginning of block
Nonlocal In nested block (No declaration, use implicit extern)
File Static In function Define as SHARE before first function in file
Declare as IMPORT at beginning of each function where referenced
Program Static In function Define as EXPORT before first function in file where variable is to be allocated
Declare as IMPORT before first function in file(s) where variable is used
Declare as IMPORT at beginning of each function where referenced
Declaring Functions
Callable from Visibility specifier
Same file (only) SHARE
Any file EXPORT

The SHARE macro isn't a silver bullet to slay all of C's visibility monsters, nor does it boost C's visibility features into a class with Modula 2's. But it makes a lot more sense to write SHARE rather than static when you're trying to specify a variable's visibility.

In functions or blocks where you want to use a SHARE variable, declare the variable with the IMPORT macro:

void func1( void ) {
IMPORT x;
...
}

This declaration expands to

extern int x;

which, although unnecessary given C's default scoping rules, makes explicit the function's intention to use x. Unfortunately, C won't protect you against unintentional references to x in functions that don't declare x. Reducing the number of nonlocal variables is the best way to reduce accidental nonlocal references.

You also should specify SHARE for functions you intend to be callable only from within the same file. Use EXPORT for functions you intend to be callable from anywhere. Functions without a visibility specifier default to EXPORT, but I find explicit visibility reminds me which functions are callable from anywhere. (I often notice EXPORT functions that don't need such broad visibility and that are better defined as SHARE.) In addition, by grouping all SHARE functions after all EXPORT functions, you can organize your functions better.

For export variables you want visible throughout all source files (i.e., the entire program), use the EXPORT macro to declare (and define) the variable before the first function definition in the file "owning" the variable. In most cases, this is the file containing the main function.

The following example shows how to define an export variable:

EXPORT int x = 0;

This statement expands to

int x = 0;

which gives x the desired visibility and allocates storage for x. It's good programming practice to initialize variables in their definitions, especially variables for which C's default zero initialization is not within the variable's domain (valid values). I'd also recommend you place all EXPORT variable declarations before any IMPORT declarations. Note that, as with SHARE, you never use EXPORT inside a function.

In functions where you want to use a nonlocal variable, declare the variable with IMPORT at the beginning of the function:

void func1( void ) {
IMPORT x;
...
}

The IMPORT declaration adds the necessary extern specifier and clearly shows that the function uses a nonlocal variable. A variable declared as IMPORT in a function will resolve to one of the file's SHARE or IMPORT external declarations.

In files where you want to use a variable exported from another file, declare the variable with IMPORT once at the beginning of the file and once in each function or block where you want to use the variable. For example,

| Before first function
*/


IMPORT x;
...
void func1( void ) {
IMPORT x;
...
}

The first IMPORT declaration adds the necessary extern specifier and clearly indicates that x is defined in another file and that x may be used in other files (as well as in the current file and in the one that defines it). Like the previous example, the second IMPORT identifies a nonlocal variable used in a function. In this case, the two IMPORT declarations are clearly warning that func1 uses a variable that functions in other files also might use.

Finding Your C Legs

SHARE, EXPORT, and IMPORT let your declarations "say what they mean and mean what they say." You may prefer different macro names; almost any descriptive names produce clearer code than C's standard syntax. I picked up the idea for the macros from Steve Schustack's suggestion in Variations in C for similar macros he calls GLOBAL, SEMIGLOBAL, and IMPORT. I think EXPORT indicates better than GLOBAL the role of a variable allocated in one file and made available to other files, and SHARE seems more informative than SEMIGLOBAL. But whatever names you choose, these simple "visibility" macros and guidelines for declarations will let you, and anyone who reads your programs, C clearly now.

C Coding Suggestions

*  Declare functions static if you intend to call them only from within the same source file.
*  Use the most restricted visibility possible for variables; avoid shared variables.
*  Put all external declarations before the first function definition in a file.
*  Put functions that must share data and external declarations for their shared variables in a file by themselves.
*  Use EXPORT, SHARE, and IMPORT macros to clarify the intended visibility of a variable.


Previous Table of Contents Next