Globals In Headers

There has been a growth again of variables being declared & instantiated in the header files.

It works, but I believe it is a non-portable habit, which is perhaps reason enough to ban them; it has traditionally been supported by Unixy systems (and hence the gcc toolchain), but not other systems. (I learnt C on a VAX, which is probably why the notion of storage in headers gives me such a grue...)

Also the way it works is remarkably subtle and leads to some, ah, interesting questions about life the universe and bugs.

You see, as reference (1) says, when you declare an uninitialized global, the compiler (at least Unixy ones) emit a "weak" symbol.

The linker then uses the strong symbol with that name, (or whinges about "multiply defined symbols" if it finds more than one "strong" symbol). If there are only weak versions, it uses any one.

A downside of that habit is this is using the Ye Olde Fortran "common block" trick.

If you are an old Fortran programmer such as myself, your skin should be crawling at this stage.

For example, if you have, in a file a.c

 ----a.c

int fred;

-------
and in another file b.c

 ----b.c

unsigned int fred;

----
The toolchain allows you to stuff signed int's in one side and eat unsigned ints on the other!

Madness lies that way. Been there done, done that, still gibbering.

Now I will admit straight off that this isn't a problem that arises out of declaring storage in headers.

However the habit of declaring storage in headers precludes me from switching on a linker warning to that will stop the above noxious case.

The standard way around declaring storage in the header is...

 ----a.h
 #undef scope
 #ifdef A_C
 #define scope
 #else
 #define scope extern
 #endif

scope int fred; ------

----a.c #define A_C #include "a.h" ---------
This is all very nice and all, but I must also remind you that GlobalVariablesAreBad are really pretty noxious things in themselves and I would beg you to keep them to a minimum.


(1) "Computer Systems: A Programmer's Perspective" Chapter 7 Linking

http://csapp.cs.cmu.edu/public/ch7-preview.pdf


I don't think so. Correct me if I'm wrong here, but the standard way of declaring global storage is very similar to the standard way of declaring functions. Neither one requires any #define or #undef statements. Those #define and #undef statements just make things more complicated than they need to be. The standard way is:

  ---- something_useful.h
  extern int fred;
...

  ---- something_useful.c
  #include something_useful.h
  int fred;
...

  ---- main.c
  #include something_useful.h
...
      fred = 8;
...

This C idiom allows the compiler to double-check the consistency of the header file against the actual definition. Any other method (that attempts to avoid the "redundancy" of declaring both "extern int fred" and "int fred" while compiling something_useful.o) risks losing synchronization between the declaration ("prototype") of the variable in the header file, and the actual definition (in one and only one .c file). -- DavidCary


CeePreprocessorStatements CategoryCodingIssues CategoryCee CeeIdioms CategoryCpp


EditText of this page (last edited December 9, 2005) or FindPage with title or text search