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?