Multiple definition of a global variable is not allowed in C or C++ due to the One Definition Rule. However, in C++ a const global variable can be defined in multiple compilation units with no error. This is not the same as in C.
Why does C++ allow this while C does not? Why does the usage and behaviour of a const global differ from a non-const global in this way in C++ compared to C? What is happening under the covers with C++ and C with respect to const?
For example this is allowed in C++, but wrong in C:
// Foo.cpp
const int Foo = 99;
// Main.cpp
const int Foo = 99;
int main()
{
cout << Foo << endl;
return 0;
}
And this is fine with C, but wrong with C++:
// Foo.cpp
const int Foo = 99;
// Main.cpp
extern const int Foo;
int main()
{
cout << Foo << endl;
return 0;
}
The disadvantage of #define is that is replaces every occurence of the name, while const variables get normal lookup, so you have less risk of naming conflicts and it's not typesafe.
In general, const is a better option if we have a choice and it can successfully apply to the code. There are situations when #define cannot be replaced by const. For example, #define can take parameters (See this for example). #define can also be used to replace some text in a program with another text.
Global variables aren't constant (you can change the value of a global variable, but you can only define a constant once). Constants aren't always global (you can declare a constant in a class). Also, global variables can be any type: scalar, array, or object. Constants can only be scalars.
The const keyword allows you to specify a semantic constraint: an object should not be modified. And compilers will enforce that constraint. This will allow you to communicate to the compiler and to other developers that the object should remain invariant.
// Foo.cpp
const int Foo = 99;
// Main.cpp
const int Foo = 99;
const
variable at namespace scope has internal linkage. So they're basically two different variables. There is no redefinition.
From @David's comment, 3.5/3 [basic.link]:
A name having namespace scope (3.3.5) has internal linkage if it is the name of
— an object, reference, function or function template that is explicitly declared static or,
— an object or reference that is explicitly declared const and neither explicitly declared extern nor previously declared to have external linkage; or
— a data member of an anonymous union.
In the second case, you should be doing this (correct way):
//Foo.h
extern const int Foo; //use extern here to make it have external linkage!
// Foo.cpp
#include "Foo.h"
const int Foo = 99; //actual definition goes here
// Main.cpp
#include "Foo.h"
int main()
{
cout << Foo << endl;
}
I think you are asking for the rationale and not the specific language rule that allows this.
The rationale for this is that it makes const
variables much easier to use. It gives a typed replacement for one common use of #define
.
Instead of #define MAX_COUNT 211
you can use const int max_count = 211;
in exactly the same way, e.g. a shared header file, without having to worry about where to put the one definition.
You can't legally change the value of a const
object so there's no visible difference between having one object and multiple objects with the same value.
As you can put a definition of a const
object in a header file it makes trivial for the compiler to use the value directly at the compilation stage without such optimizations having to be delayed to a link-time fixup.
Basically, in C++, const, non-local variables are genuine constant expressions, or constexpr. This permits plenty of things, like TMP.
const int five = 5;
int main() {
int x[five];
std::array<int, five> arr;
}
In C, they are just a variable that cannot be modified. That is,
const int five = 5;
int main() {
int x[five]; // Technically, this is a variable length array
}
Is quite equivalent to
int five = 5;
int main() {
int x[five];
}
Effectively, C++ promotes some kinds of const
variable to a new category, constexpr
, whereas in C, this does not exist and they are just variables which happen to be unmodifiable.
It looks like const doesn't actually generate an external symbol.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With