11

I want to provide a string constant in an API like so:

extern const char* const SOME_CONSTANT;

But if I define it in my static library source file as

const char* const SOME_CONSTANT = "test";

I'm getting linker errors when linking against that library and using SOME_CONSTANT:

Error 1 error LNK2001: unresolved external symbol "char const * const SOME_CONSTANT" (?SOME_CONSTANT@@3QBDB)

Removing the pointer const-ness (second const keyword) from both the extern const char* const declaration and the definition makes it work. How can I export it with pointer const-ness?

AndiDog
  • 68,631
  • 21
  • 159
  • 205

3 Answers3

14

The problem could be that the extern declaration is not visible in the source file defining the constant. Try repeating the declaration above the definition, like this:

extern const char* const SOME_CONSTANT;  //make sure name has external linkage
const char* const SOME_CONSTANT = "test";  //define the constant
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • That works. I was just wondering how the linker knows it shouldn't strip my symbol... and then I saw your answer and facepalmed :D Of course I have to enforce extern linkage. – AndiDog Feb 20 '13 at 10:13
  • 3
    @AndiDog Note that this is the same as just adding `extern` to the definition. As the other answer suggests, `const` in C++ implies `static`. So you need to counteract that and explicitly say `extern` in your definition too. – Nikos C. Feb 20 '13 at 10:16
  • 1
    "`const` in C++ implies `static`... This seems like an arbitrary hack in C++ specification. Micro optimization for lazy people!!! – FooF Feb 20 '13 at 10:23
  • 4
    instead of repeating the declaration, which is contrary to the **DRY** (Don't Repeat Yourself) principle, either (A) include your header file in the implementation, or (B) add the keyword `extern` only. Well, as suggested in my answer. I didn't suggest the code repetition, because it serves no useful purpose: it's very ungood. – Cheers and hth. - Alf Feb 20 '13 at 10:40
9

most probably you forgot to include your header in your implementation file

anyway, add the keyword extern to the definition

without an extern declaration it has internal linkage and is thus not visible to the linker

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • This seems true (tested with recent `gcc` in Linux), +1 for you. Why is that so ? What is the rational here? To make sure that header file declaration and definition match? Any link to explanation for this perplexing behavior? – FooF Feb 20 '13 at 10:19
  • re the rationale, why non-`extern` constants have internal linkage in C++, i think it has to do with avoiding needless name collisions and One Definition Rule clashes for linking. C99 has a feature that's *like* it but not exactly the same rules (i'm not sure of the details). essentially it means that you can more freely declare *and define* constants in header files. You may consider moving your constant definition to the header file, and then simply omit the `extern`. You could then add a `static` for good measure, but it's not required: that's what it's all about. – Cheers and hth. - Alf Feb 20 '13 at 10:22
  • Like you mention, there is always the well known possibility of defining `static const char * const SOME_CONSTANT = "test";` in the header file. Or we could place the definition in anonymous name space in the header... This still seems to me like a stupid hack that just adds needless complexity to the language definition!!! Maybe it is was considered more readable for header files not to be cluttered with `static` or anonymous namespace embraces. – FooF Feb 20 '13 at 10:31
  • @FooF: well, there are some subtleties for arrays and references... ;-) – Cheers and hth. - Alf Feb 20 '13 at 10:33
  • I am morbidly curious (it is quite a while since I programmed in C++)... Any links or explanations about the subtleties? – FooF Feb 20 '13 at 10:44
  • 1
    @FooF: oh, the issue is that a reference or an array can't be `const` in itself. i'm sorry i don't have at hand any discussion of it. but you may possibly google it successfully or use the SO search facility, and anyway, a bit of experimentation can be enlightening. just to be clear, i'm not entirely sure about the status for arrays. it's perhaps worth an SO question... :-) – Cheers and hth. - Alf Feb 20 '13 at 10:45
0

The solution of the accepted answer can be done in a single step.

You may add the extern specifier to the contants' definition.

extern const char* const SOME_CONSTANT = "test";
Sam Ginrich
  • 661
  • 6
  • 7