Using Constants in Headers

Started by
19 comments, last by the_edd 11 years, 4 months ago
Hello,

I have been running into a problem in my code lately. I have a file called "Constants.h" and one called "Constants.cpp." I define all my constants there. However, when I include Constants.h in another .h file I always get compile errors when, for example, trying to allocate arrays of a GIVEN_CONSTANT size. Is there a reason for this? I never get these errors in .cpp files. It seems like the pre-processor is not expanding my #includes into the header, or maybe there is a rule that constants can't be used in headers in c++? Can someone shed some light on this situation for me?

Thanks.

- Dave Ottley

I wonder as I wander...

http://www.davesgameoflife.com

Advertisement
It would help to see what your code actually looks like and what compiler errors you're actually getting.
I'll give you an example. This is not exact because I have already fixed the errors with a workaround. But, for example

Constants.h:
extern const int MAX_INTS;

Constants.cpp
extern const int MAX_INTS = 1000;

Foo.h
#include "Constants.h"
class Foo {
int bar[MAX_INTS];
void DoSomething();
};

Compiler Error: "Arrays must be initialized with a constant."

*NEW* Foo.h
#include "Constants.h"
const int MAX_INTS = 1000;
class Foo {
int bar[MAX_INTS];
void DoSomething();
};

Compiles fine.

I wonder as I wander...

http://www.davesgameoflife.com

As the constant is defined in a different translation unit, it's value cannot be known at compile time, only at link time.
[size="1"]
Why aren't you putting the constants in the header?
Simply write this in your header file, and nothing in the .cpp file:
const int MAX_INTS = 1000;
First of all, in your Constants.cpp file you need to write "const int MAX_INTS = 1000; "
The extern keyword means "declare without defining". In other words, it is a way to explicitly declare a variable, or to force a declaration without a definition.

The practice itself (putting the initialization into the cpp file) is a matter of personal taste. I personally like it because if i need to change the value for whatever reason, not every single file which includes the header file is compiled again.

But i wouldnt use "extern" anymore....i like static const uint32 MAX_INTS; in a header file more. ;-)
.

Simply write this in your header file, and nothing in the .cpp file:
const int MAX_INTS = 1000;


That will of course solve the problem, but for the OP's benefit I think it might be worth giving a little more background on why 'extern' isn't needed here.

For example, you can't put "int MAX_INTS = 1000;" in a header file without opening yourself up to ODR violations, despite the trivial visual differences between this definitions and "const int MAX_INTS = 1000;".

Muddying the waters further are differences in semantics between C and C++.

In C++, a definition such as "const int MAX_INTS = 1000;" defines the MAX_INT object with internal linkage. This means that if the definition resides within a header, and that header is #included in to multiple translation units, you're really creating a number of distinct objects (though I think a linker could still put them all at the same location in the end, as a space optimization).

However, "int MAX_INTS = 1000;" defines an object with external linkage because MAX_INTS is not const. This means that if this definition resides within a header, and that header is #included in to multiple translation units, you're defining a single object multiple times. This is an ODR (one definition rule) violation, which says (approximately) that objects with external linkage must have a single definition across the entire program. So in this case, the correct thing to do is indeed to declare MAX_INTS with 'extern' in a header, and then define it in a single translation unit.

In C, everything we've seen so far has external linkage. If you want to put a constant in a header, you either use a #define instead, or put 'static' in front of the definition to give each copy of the variable internal linkage within their respective translation units. You can also use 'static' in the C++ definitions too without causing harm, except for the redundant keyword.

There are some other rules too, making the whole subject quite intricate. But the important things to understand are the concepts of internal and external linkage. Knowledge about how and when definitions and declarations affect linkage will come with time and practice.

(Edited to remove incorrect stuff about floats).
Thank you all for your comments. I have decided to go with the

#ifndef
#define MAX_INTS 1000
#endif

route because it doesn`t waste any memory. I can`t see a downside to it either, and this is how the Microsoft .h files are organized. Until next time...

- Dave Ottley

I wonder as I wander...

http://www.davesgameoflife.com

This topic is closed to new replies.

Advertisement