3

I was experimenting with GCC and found out that you can declare variables const in header files but keep them mutable in implementation files.

EDIT: This does actually not work, check my own answer.

header.h:

#ifndef HEADER_H_
#define HEADER_H_

extern const int global_variable;

#endif

header.c:

int global_variable = 17;

This makes global_variable modifiable to the implementation but const to every file that includes header.h.

#include "header.h"

int main(void)
{
    global_variable = 34; /* "header.h" prevents this type of assignment. */
    return 0;
}

Is this technique used in practise?

People often recommend using get-functions to retrieve global state when building interfaces in C. Are there any advantages to that approach over this?

To me this approach seems to be a lot more clearer and does not have the added overhead of a function call each time someone tries to access global_variable.

wefwefa3
  • 3,872
  • 2
  • 29
  • 51
  • 1
    Several of the answers are written under the assumption that the C++ tag is there because it was earlier, voters please keep this in mind. –  Jan 01 '15 at 22:57
  • 1
    possible duplicate of [Declaring a global variable \`extern const int\` in header but only \`int\` in source file](http://stackoverflow.com/questions/27724453/declaring-a-global-variable-extern-const-int-in-header-but-only-int-in-sourc) –  Jan 02 '15 at 02:03
  • While I would like this feature very much (it could be quite useful when working with legacy code that uses globals, when writing low-memory-footprint programs, or in similar situations), it sadly isn't standards-compliant, nor is any compiler that allows it. I believe it would be relatively easy to introduce a manner to do so by copying pre-existing syntax (such as `extern "const"`, based on `extern "C"` syntax), but might be a bit harder for compilers to implement (as it would require modifications to the name mangler, to keep track of the actual type). – Justin Time - Reinstate Monica Mar 23 '16 at 20:00
  • I also feel that it's of such limited use that it might be rejected even if it were to be proposed, but that's just speculation. – Justin Time - Reinstate Monica Mar 23 '16 at 20:01

4 Answers4

4

Both approaches are used in practice, but the best practice in most cases is to avoid global variables and static state.

Note: your question is tagged C and C++, this is the C++ approach.

A better approach is to create a class containing your "global" state and pass it around to functions that would otherwise need global variables and constants. This is called a "context."

The context object can use proper information hiding to control who can update its state, validating its state, etc. just like any other object. Plus it completely avoids the need for global variables, which are an anti-pattern.

  • 2
    Certainly, not an approach to use in C++. `int a` and `int const a` are differently mangled on some compilers. And by the letter of law, too, that's an example of UB: the same name is given conflicting definitions. – ach Dec 31 '14 at 17:25
  • @AndreyChernyakhovskiy I had started writing about how `int` and `const int` are technically different data types when I realized that was not really addressing the big picture. Using the approach in my answer, that and a number of potential problems with header files and compilation units are eliminated. –  Dec 31 '14 at 17:48
  • This is not merely the C++ approach. Most good object-oriented C APIs use a context object hidden behind a `void*`. Glib, GTK+, EFL, Cairo, and many others are like this, and avoid holding global state wherever possible. – greyfade Jan 01 '15 at 00:11
3

This is actually not valid.

Take this example.

header.h:

#ifndef HEADER_H_
#define HEADER_H_

extern const int global_variable;

#endif

header.c:

#include "header.h"

int global_variable; // Here will the compiler complain!

This will not compile because int and const int are not compatible types. The only reason I got my own test to work was because I did NOT include "header.h" in "header.c".

wefwefa3
  • 3,872
  • 2
  • 29
  • 51
2

get functions allow new logic (e.g. validation) to be inserted later. If you start out with a global variable and find out later that you need new logic, adding a get function is a breaking change.

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
0

This is a pre-C++11 way of doing, that may have some pitfalls: in fact it relies on the linker to sustain the resolution. If all values are simple it's not a big problem, but if a value is not a POD and depends on others, since the linking order is not specified by the sources, this may expose to the "global initialization fiasco".

Inside header files it may sometimes have a more straightforward approach a

static constexpr int global_constant = xx;

the static keyword makes the global_constant local to each independent translation unit, avoiding the need of a "universal global object" to be defined only once.

This approach is also compatible with the "header only libraries", that are a must with generic code.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63