Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is multiple definition of a const global variable allowed in C++ and not in C?

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;
}
like image 233
Ashwin Nanjappa Avatar asked May 30 '11 08:05

Ashwin Nanjappa


People also ask

Why should you not use #define to declare a constant?

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.

Is const better than #define in C?

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.

Can a global variable be constant?

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.

Why would you use const sometimes?

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.


4 Answers

// 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;
}
like image 51
Nawaz Avatar answered Oct 10 '22 17:10

Nawaz


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.

like image 33
CB Bailey Avatar answered Oct 10 '22 19:10

CB Bailey


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.

like image 6
Puppy Avatar answered Oct 10 '22 18:10

Puppy


It looks like const doesn't actually generate an external symbol.

like image 3
Alex B Avatar answered Oct 10 '22 18:10

Alex B