Reputation: 396
Apologies if this has been asked before. I searched the internet and did not find an answer.
Say I have a file Common.h
, and A.cpp
and B.cpp
include Common.h
.
If I want to have a global const char *
in the Common
translation unit, I must make it extern
in Common.h
, and define it in Common.cpp
. Otherwise, if I simply define const char * MSG = "Hello World";
in Common.h
, I get a duplicate symbol
error during compilation.
However, if I simply define a global const int in Common.h
with a statement like const int CONSTANT = 10;
then the code compiles without a duplicate symbol error, and everything works fine.
I am confused as to why this is the case. It seems to me here that the only difference between the two examples above is the type, which I think shouldn't make a difference. Why do I get the duplicate symbol error for C-strings, but not ints?
Suppose main.cpp
, A.h
, B.h
, A.cpp
, and B.cpp
look as follows:
// A.h
#pragma once
void f();
// A.cpp
#include "A.h"
#include "Common.h"
#include <iostream>
void f() {
std::cout << MSG << std::endl;
}
// B.h
#pragma once
void g();
// B.cpp
#include "B.h"
#include "Common.h"
#include <iostream>
void g() {
std::cout << CONSTANT << std::endl;
}
// main.cpp
#include "A.h"
#include "B.h"
int main()
{
f();
g();
}
Now, suppose we take compile with the command g++ main.cpp A.cpp B.cpp Common.cpp -std=c++14
.
If we make Common.h
and Common.cpp
the following, then compilation fails with error duplicate symbol MSG
:
// Common.h
#pragma once
const char * MSG = "Hello World";
const int CONSTANT = 10; // defined in header file
// Common.cpp
// empty
However, this compiles:
// Common.h
#pragma once
extern const char * MSG;
const int CONSTANT = 10; // defined in header file
// Common.cpp
#include "Common.h"
const char * MSG = "Hello World";
I am wondering why we need extern and to separate definition & declaration for the string, but not for the int.
Someone suggested making the C-string type as const char * const
instead of const char *
. Why does making the pointer const work? Also, in this case, what is the difference between this solution and the solution I provided above (where we make the string extern instead and split definition/declaration)? Why do both methods solve the compilation error and what is the difference between the methods?
I noticed also that if I turn const int
into just int
, then I get the duplicate symbol
error again. I feel like the reason behind this is related to the answer to my questions above. Why is this the case?
Upvotes: 2
Views: 616
Reputation: 6085
This is one of the differences of C and C++.
In C++ a const
variable is implicitly static
, i.e. only visible to the current translation unit. In C it is implicitly extern
so visible to the entire program (which is also the default for the other non-const declararions in both C and C++).
This explains your observation.
Note: A const char *p
declaration of a variable is not a const
variable. It means it points to a const variable (i.e. *p
is cannot be modified), but p
itself is not const
. So behavior here is different. const char * const p
would be a const declaration.
Upvotes: 4