J
Jack Klein
I'm looking for opinions on a C technique I, and others, have used
successfully in the past. While some people swear by, apparently
others swear at it.
Assume a part of a program too large to fit comfortably in a single
source file, call it a "module". Let's call it "module A".
Also assume for various reasons module A needs a private data store
with static storage duration, accessible from files in more than one
translation unit. For a number of reasons it is necessary to have the
stored objects directly accessible where they are needed, so accessor
functions are ruled out.
Which leaves objects with external linkage.
To about name conflicts, all of module A's objects have names starting
with "moda_". Since they are referenced by name in several source
files, they must be defined in one, and declared as external in the
others.
Possibility 1:
They are just defined in one source file and matching extern
declarations are added to the others.
The big downside of this the files getting out of sync as
modifications are made. Maybe caught by the linker, maybe undefined
behavior at run time.
Possibility 2:
They are declared in a header file, and defined in a separate source
file that contains nothing else but the definitions.
Easier to keep in sync, anyone modifying such an object changes the
header file, then copies and pastes it into the C file, finally does a
search and replace of "extern" with nothing in the C file.
Less chance of getting out of sync, but still possible.
Possibility 3, which is possibility 2 automated with a little help
from the preprocessor:
File moda_vars.h:
#ifndef MODA_VARS_H
#define MODA_VARS_H
#ifdef DEFINE_MODA_VARS
#define MODULE
#else
#define MODULE extern
#endif
MODULE int moda_x;
MODULE int moda_y;
/* etcetera */
#endif /* MODA_VARS_H */
<eof>
File moda_vars.c:
#define DEFINE_MODA_VARS
#include "moda_vars.h"
<eof>
Files moda_code_1.c, moda_code_2.c, etc...
#include "moda_vars.h"
/* no definition of DEFINE_MODA_VARS */
The major point of option 3 is that there is no way that the
definitions of the objects and the external declarations can ever get
out of sync. Assuming a typical (and off-topic) build tool that
handles dependencies, any change to the header file forces a fresh
build of all the source files, definer and users.
In the situations where I've used this technique there is generally no
need to provide other than the default 0 initialization of static
objects, although there are somewhat more elaborate macros that allow
initializer expressions to be visible to the compiler in the defining
file and invisible in those that see the extern declarations.
I am not asking for opinions on whether or not the use of such shared
objects is a good idea, although this being comp.lang.c I'm sure I'll
get some.
What I am interested in is opinions on using a technique like
possibility 3, or any experiences anyone might care to share with
using something like this.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
successfully in the past. While some people swear by, apparently
others swear at it.
Assume a part of a program too large to fit comfortably in a single
source file, call it a "module". Let's call it "module A".
Also assume for various reasons module A needs a private data store
with static storage duration, accessible from files in more than one
translation unit. For a number of reasons it is necessary to have the
stored objects directly accessible where they are needed, so accessor
functions are ruled out.
Which leaves objects with external linkage.
To about name conflicts, all of module A's objects have names starting
with "moda_". Since they are referenced by name in several source
files, they must be defined in one, and declared as external in the
others.
Possibility 1:
They are just defined in one source file and matching extern
declarations are added to the others.
The big downside of this the files getting out of sync as
modifications are made. Maybe caught by the linker, maybe undefined
behavior at run time.
Possibility 2:
They are declared in a header file, and defined in a separate source
file that contains nothing else but the definitions.
Easier to keep in sync, anyone modifying such an object changes the
header file, then copies and pastes it into the C file, finally does a
search and replace of "extern" with nothing in the C file.
Less chance of getting out of sync, but still possible.
Possibility 3, which is possibility 2 automated with a little help
from the preprocessor:
File moda_vars.h:
#ifndef MODA_VARS_H
#define MODA_VARS_H
#ifdef DEFINE_MODA_VARS
#define MODULE
#else
#define MODULE extern
#endif
MODULE int moda_x;
MODULE int moda_y;
/* etcetera */
#endif /* MODA_VARS_H */
<eof>
File moda_vars.c:
#define DEFINE_MODA_VARS
#include "moda_vars.h"
<eof>
Files moda_code_1.c, moda_code_2.c, etc...
#include "moda_vars.h"
/* no definition of DEFINE_MODA_VARS */
The major point of option 3 is that there is no way that the
definitions of the objects and the external declarations can ever get
out of sync. Assuming a typical (and off-topic) build tool that
handles dependencies, any change to the header file forces a fresh
build of all the source files, definer and users.
In the situations where I've used this technique there is generally no
need to provide other than the default 0 initialization of static
objects, although there are somewhat more elaborate macros that allow
initializer expressions to be visible to the compiler in the defining
file and invisible in those that see the extern declarations.
I am not asking for opinions on whether or not the use of such shared
objects is a good idea, although this being comp.lang.c I'm sure I'll
get some.
What I am interested in is opinions on using a technique like
possibility 3, or any experiences anyone might care to share with
using something like this.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq