[comp.lang.c] Initialization in #include files

vlcek@mit-caf.UUCP (Jim Vlcek) (06/06/88)

In article <851@.UUCP* peter@ficc.UUCP (Peter da Silva) writes:
*It's a good idea to stick your declarations and initialisation
*in one place. When you change a variable, or add one, or delete one, you
*really need to make sure you get all the declarations. It's much more
*convenient if it's all in one place.
*
*But, do it intelligently:
*
*---- foo.h
*#ifdef FOO_C
*#define GLOBAL
*#define INIT(x) =x
*#else
*#define GLOBAL extern
*#define INIT(x)
*#endif
*
*GLOBAL char *fooname INIT("foo");
*GLOBAL char *footype INIT("program");
*
*#undef GLOBAL
*#undef INIT
*----
*
*And then:
*
*---- foo.c
*#define FOO_C
*
*#include "this.h"
*#include "that.h"
*#include "foo.h"
*#include "the_other.h"
*-- 
*-- Peter da Silva, Ferranti International Controls Corporation.
*-- Phone: 713-274-5180. Remote UUCP: uunet!nuchat!sugar!peter.

If one changes/deletes a variable in an #include file, one must
comb through every source file using that #include file and
change/delete every reference to that variable.  This chore is quite
likely to dwarf the task of changing the (smaller number of)
declarations of the changed variable in the source modules which
``own'' the changed/deleted variable.

It seems to me that #include files are intended to contain only the
most generic of information: typedefs, function prototypes and macros,
generic #defines, and external variable declarations.  The ideal
#include file should give everything and ask nothing in return; the
hacks to allow initialization contain a quiet demand that I, somewhere
in my application, define a necessary constant.

It's also conceivable that the global variables specified in an
#include file may be ``owned'' by separate source modules, in which
case different #defines have to be used for each global variable, etc.

I'm frankly perplexed why people will perform such gymnastics to put
their initializations into #include files.  I only want to have to
look at the #include files when generating code, not when checking it.
I'd much rather have my initializations in the source module itself,
rather than have to try and figure out which #include file it's in,
and then hunt it down there.
-- 
Jim Vlcek
vlcek@caf.mit.edu
!{ihnp4,harvard,seismo,rutgers}!mit-eddie!mit-caf!vlcek

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/09/88)

In article <5776@chinet.UUCP> les@chinet.UUCP (Leslie Mikesell) writes:
>But the variables are very likely to be used in every source file, ...

I do hope you people know better than to design software with lots
of pathological inter-module connections like this.

les@chinet.UUCP (Leslie Mikesell) (06/10/88)

In article <8046@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>>But the variables are very likely to be used in every source file, ...
>
>I do hope you people know better than to design software with lots
>of pathological inter-module connections like this.

OK, where do *you* put all the things that have default values that can
be altered by options on the command line?  Do you use pathological
globals or pass about 50 parameters to every function called from main()?
What about state variables?  What about things that need to be cleaned
up in case of interrupts or error exits?  Somehow about 50% of the variables
seem to fall in one of these classes in a lot of my programs.
  
 Les Mikesell

gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/11/88)

In article <5791@chinet.UUCP> les@chinet.UUCP (Leslie Mikesell) writes:
>Somehow about 50% of the variables seem to fall in one of these classes
>in a lot of my programs.

All I can suggest is that you go study Yourdon and Constantine, or
Jackson, or some other structured software design text.

mouse@mcgill-vision.UUCP (der Mouse) (06/20/88)

In article <8046@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <5776@chinet.UUCP> les@chinet.UUCP (Leslie Mikesell) writes:
>> But the variables are very likely to be used in every source file,
> I do hope you people know better than to design software with lots of
> pathological inter-module connections like this.

Let's pick an example.  I wrote a dvi-to-printer program for our
printers here.  Here's the list of global variables (the .h file which
every file includes).  What would you recommend I do with each one?
All of them hold stuff which is conceptually global, ie, which should
be available to any module which cares to refer to it.

[#include blather (type definitions, eg) deleted]

	extern PAGENO veryfirst;
	extern PAGENO verylast;
These are the lowest and highest possible page numbers.  PAGENO is a
non-simple type, so these are initialized data rather than #defines.
Under ANSI they would be declared const.

	extern char *inclexcl[MAX_INCL_EXCL];
	extern int n_inclexcl;
	extern PAGENO ie_pgs[MAX_INCL_EXCL][2];
	extern int default_is_excl;
	extern int is_excl[MAX_INCL_EXCL];
These variables describe the results of parsing the command-line
options to select what pages of the dvi file to print.

	extern int debugging;
This variable turns on debugging information from various modules.

	extern char dvifile[256];
	extern FILE *dvif;
Variables describing the dvi file: name and FILE pointer.

	extern SIXVALUES *stack;
	#define h stack->H
	#define v stack->V
	#define hh stack->HH
	#define vv stack->VV
	#define w stack->W
	#define x stack->X
	#define y stack->Y
	#define z stack->Z
The stack of positions (see the dvi file format documentation).

	extern FONT *fonts;
	extern FONT *curfont;
The list of all fonts and the current font.

	extern int numerator;
	extern int denominator;
	extern double trueconv;
	extern int mag;
	extern double conv;
These hold global information obtained from the dvi file, things like
conversion ratios between dvi file units and pixels.

	extern int dvilength;
	extern int postamble;
	extern int firstbackpointer;
Stuff to help find the dvi file administrivia.

	extern int maxh;
	extern int maxv;
Maximum values of h and v (see the dvi format documentation).

	extern int npages;
	extern long int *pg_begins;
Number of pages and locations at which they begin in the dvi file.

	extern int startloc;
Set but never used (historical artifact).

	extern PRINTER *printer;
Pointer through which printer-specific routines are accessed.

	extern int Fflag;
	extern int Xflag;
Two command-line flags, to be used by the printer routines.

	extern int nfontdirs;
	extern char **fontdirs;
	extern int maxfdlen;
The results of parsing the path for font files.

	extern char defaultfontpath[];
	extern char fontpath_env[];
Initialized strings for the font file path.

	extern int missingfonts;
Indication of whether there were any fonts for which the bitmap files
could not be located.

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

peter@ficc.UUCP (Peter da Silva) (07/01/88)

In article <1021@mit-caf.UUCP>, vlcek@mit-caf.UUCP (Jim Vlcek) writes:
> In article <851@.UUCP* peter@ficc.UUCP (Peter da Silva) writes:
> *#ifdef FOO_C
> *#define GLOBAL
> *#define INIT(x) =x
> *#else
> *#define GLOBAL extern
> *#define INIT(x)
> *#endif
   ... and so on...

> If one changes/deletes a variable in an #include file, one must
> comb through every source file using that #include file and
> change/delete every reference to that variable.

If one deletes a global variable, one must comb through every source
file that might be using that variable anyway. If one changes a variable,
that's still true. Whether or not that variable is declared in an include
file (for example, _ctype in ctype.h) or not. The same is true when you
change an element of a structure declared in an include file.

I don't understand this objection at all.

> It seems to me that #include files are intended to contain only the
> most generic of information: typedefs, function prototypes and macros,
> generic #defines, and external variable declarations.

Since the external variable is declared in an include file, why not
initialise it there as well? Keeps everything nice and handy.

> The ideal
> #include file should give everything and ask nothing in return; the
> hacks to allow initialization contain a quiet demand that I, somewhere
> in my application, define a necessary constant.

Since the include file is part of your application, what's the big deal?
If it's not, then presumably the author of the library you are using
provided the necessary #define in some standard place (for example,
in ctype.c).

> It's also conceivable that the global variables specified in an
> #include file may be ``owned'' by separate source modules, in which
> case different #defines have to be used for each global variable, etc.

Right. I generally have a source file foo.c, and an accompanying include
file foo.h. The source file has FOO_C defined at the beginning of the module.

> I'm frankly perplexed why people will perform such gymnastics to put
> their initializations into #include files.  I only want to have to
> look at the #include files when generating code, not when checking it.
> I'd much rather have my initializations in the source module itself,
> rather than have to try and figure out which #include file it's in,
> and then hunt it down there.

But the include file it's in is obvious. And if I change an element in an
initialised structure from char to long, I only want to have to change it
in one place.

Anyway, I find the technique useful. Other people might, too. With the
slightest bit of discipline you need never fear inconsistent structure
definitions again!
-- 
-- `-_-' Peter (have you hugged your wolf today) da Silva.
--   U   Ferranti International Controls Corporation.
-- Phone: 713-274-5180. CI$: 70216,1076. ICBM: 29 37 N / 95 36 W.
-- UUCP: {uunet,academ!uhnix1,bellcore!tness1}!sugar!ficc!peter.

leo@philmds.UUCP (Leo de Wit) (07/03/88)

In article <1002@ficc.UUCP> peter@ficc.UUCP (Peter da Silva) writes:
>In article <1021@mit-caf.UUCP>, vlcek@mit-caf.UUCP (Jim Vlcek) writes:
 [stuff deleted]...
>> It seems to me that #include files are intended to contain only the
>> most generic of information: typedefs, function prototypes and macros,
>> generic #defines, and external variable declarations.

I can only agree. Header files are for declarations, source files for
definitions.

>Since the external variable is declared in an include file, why not
>initialise it there as well? Keeps everything nice and handy.

Why not put the functions there as well? What makes functions different
from variables with respect to declaration and definition? In this manner
you can do everything with only header files. Boy, that will make things
really clear 8-).

>> The ideal
>> #include file should give everything and ask nothing in return; the
>> hacks to allow initialization contain a quiet demand that I, somewhere
>> in my application, define a necessary constant.

My idea. The header file is the (outgoing) interface of a source module
to the outside world.

>Since the include file is part of your application, what's the big deal?
>If it's not, then presumably the author of the library you are using
>provided the necessary #define in some standard place (for example,
>in ctype.c).

The big deal, as you put it, is that you use header files for purposes
they weren't meant to deal with. I sometimes see beginning C programmers
put functions in .h files, then include those .h files in their
programs to have the functions available. If you really need to do this
(but I can hardly think of a good reason) use a separate .c file to put
the stuff in.

>> I'm frankly perplexed why people will perform such gymnastics to put
>> their initializations into #include files.  I only want to have to
>> look at the #include files when generating code, not when checking it.
>> I'd much rather have my initializations in the source module itself,
>> rather than have to try and figure out which #include file it's in,
>> and then hunt it down there.
>
>But the include file it's in is obvious. And if I change an element in an
>initialised structure from char to long, I only want to have to change it
>in one place.

You still have to adjust each usage of that element.

>Anyway, I find the technique useful. Other people might, too. With the
>slightest bit of discipline you need never fear inconsistent structure
>definitions again!

Sorry to disagree with you Peter, but I don't share your opinion. The
whole idea is like a magic trick. And if you're out for tricks, you
could just as well put all source in one file, distinguishing between
modules with an ifdef surrouding each module in the file 8-) (smiley
added to ensure that people will not take this as a serious
possibility).

You need never fear inconsistent structure definitions with header
files, as you should typedef them once in the header file, then use
that type throughout the code. As for difference in types for
declaration and definition, every decent compiler should (at least)
complain.

       Leo.

bill@proxftl.UUCP (T. William Wells) (07/05/88)

In article <548@philmds.UUCP>, leo@philmds.UUCP (Leo de Wit) writes:
)                                                                   The
) whole idea is like a magic trick. And if you're out for tricks, you
) could just as well put all source in one file, distinguishing between
) modules with an ifdef surrouding each module in the file 8-) (smiley
) added to ensure that people will not take this as a serious
) possibility).

Unfortunately for your humor, I have actually seen that done!
The rational was something like: multiple source files are a
pain.  My response was obscene.

peter@ficc.UUCP (Peter da Silva) (07/07/88)

OK. I do this. I find it useful. I have found it useful for some years now
when I have a lot of modules. I thought some other people would also find
it a useful technique for a certain class of problem. Apparently it's
not politically correct to do things this way, because it upsets the moral
purity of include files...

I thought this was comp.lang.c, not alt.flame.
-- 
-- `-_-' Peter (have you hugged your wolf today) da Silva.
--   U   Ferranti International Controls Corporation.
-- Phone: 713-274-5180. CI$: 70216,1076. ICBM: 29 37 N / 95 36 W.
-- UUCP: {uunet,academ!uhnix1,bellcore!tness1}!sugar!ficc!peter.