6

I'm confused about why I need extern or not for int vs char* in the definition in my extern.cpp file. I have the following test program:

// extern.cpp
extern const int my_int = 1;
const char* my_str = "FOO";
// main.cpp
#include <iostream>

extern const int my_int;
extern const char* my_str;

int main() {
  std::cout << my_int;
  std::cout << my_str;
  return 0;
}

If I remove the extern from extern const int my_int = 1; then I get undefined reference to 'my_int'. If I add extern to const char* my_str = "FOO"; then I get a warning 'my_str' initialized and declared 'extern'. Why do I need extern on my_int but adding it to my_str generates a warning?

This is C++17 on gcc 10.1.0. The specific commands are:

/usr/bin/g++-10  -g -std=gnu++17 -o main.cpp.o -c main.cpp
/usr/bin/g++-10  -g -std=gnu++17 -o extern.cpp.o -c extern.cpp
/usr/bin/g++-10  -g main.cpp.o extern.cpp.o -o TestExtern
Joel Bodenmann
  • 2,152
  • 2
  • 17
  • 44
Thomas Johnson
  • 10,776
  • 18
  • 60
  • 98
  • 4
    `my_str` is not `const` – user253751 Jan 20 '21 at 16:30
  • 3
    Does this answer your question? [When to use extern in C++](https://stackoverflow.com/questions/10422034/when-to-use-extern-in-c) –  Jan 20 '21 at 16:30
  • 1
    I was wrong actually @Trovor explains why `const` has issue with `extern` – Slava Jan 20 '21 at 16:37
  • `extern` is never intended to be used with initialization. Use `extern` in header files and then in some `c` or `cpp` file define the actual variable, without using `extern`. The `extern` declaration from the header file can be in scope and its types will have to match. – Zan Lynx Jan 20 '21 at 16:39
  • So if you change `my_str` to `const char * const my_str` then you will have the same issue. – Slava Jan 20 '21 at 16:40
  • Not sure the duplicate is good. This question is really about a misunderstanding of `const` not about `extern`. – john Jan 20 '21 at 16:40
  • @john there is an answer provided by Trovor which address exactly this issue – Slava Jan 20 '21 at 16:42
  • @Slava Not really because I think the OP misunderstanding is about the meaning of `const` when applied to a pointer. But Andrey deals with this point below, so I guess it doesn't matter. – john Jan 20 '21 at 16:43

1 Answers1

12

This is caused by different linkage of my_int and my_str variables.

my_int is a const-qualified variable in namespace scope, which means it has internal linkage by default. In other words, its visibility is limited to the current translation unit, unless you mark it extern. Additionally, internal linkage constants must have an initializer.

my_str, on the other hand, is not const-qualified. Don't be confused by the const qualifier in the pointer type, as that qualifier is part of the pointed type. The pointer itself is mutable, and you could assign it a different value in run time. Since this is a non-const variable in namespace scope, it has external linkage, and as such refers to a single pointer object in the scope of the whole program.

Andrey Semashev
  • 10,046
  • 1
  • 17
  • 27
  • 1
    You've got your internal linkage a bit wrong. Constants are not necessarily internal. You can declare an `extern const int` but don't try to set it to anything. That will create a linker reference to the actual definition of the `const int`. It will not be able to inline the const int into the code unless you use LTO but it will be able to reference it via its memory location. – Zan Lynx Jan 20 '21 at 16:41
  • @ZanLynx I've updated the wording. I was talking about constants not explicitly marked as `extern`. – Andrey Semashev Jan 20 '21 at 16:45
  • This is also important: https://stackoverflow.com/a/178259/1387438 – Marek R Jan 20 '21 at 16:45
  • 1
    This is a great reason to write `char const *` instead. It's the same type, but makes it clearer that the pointed-to value is what is const. The syntax `const X` should IMO never be used. `const` always goes to the right of the part of the type it applies to; it's allowed on the left in some cases for historical reasons, but this creates confusion. In this case the example types would be `int const` and `char const *` and now we can much more clearly see that the pointer value is not const because `const` is not the last token in the type. – cdhowie Jan 20 '21 at 17:42
  • 2
    @cdho west const worst const east const best const – Yakk - Adam Nevraumont Jan 20 '21 at 18:25
  • 2
    @Yakk-AdamNevraumont [One const, two const, red const, blue const](https://genius.com/Dr-seuss-one-fish-two-fish-red-fish-blue-fish-annotated). – cdhowie Jan 20 '21 at 19:13
  • 1
    @cdhowie unfortunately there are already too many bad habits in C++ from C. Constants in UPPERCASE, `const` is usually placed wrong place, `*` binds to variable not to type etc. – Slava Jan 21 '21 at 01:59