extern const char* const SOME_CONSTANT giving me linker errors
Asked Answered
N

3

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?

Nominalism answered 20/2, 2013 at 10:4 Comment(8)
well, looks like it should be okay https://mcmap.net/q/258836/-mixing-extern-and-constBascinet
Seeing as you've tagged it C++, shouldn't a "string constant" actually be const std::string in the first place?Florineflorio
Also, is the extern declaration visible in the source file defining the constant?Florineflorio
@Angew Why would it? const char * is the C "string" type and it's perfectly valid to use it in C++.Ensile
maybe you haven't included API's header in library source?Bascinet
@H2CO3 It is perfectly valid, but it's usually more trouble than it's worth. operator+, copoying and template argument deduction come to mind.Florineflorio
@Angew: Even so, I wouldn't expose anything STL-related in a public header because other developers may use a different, not binary-compatible std::string implementation.Nominalism
@Nominalism Good point. I take my comment back (but leave it here for future readers).Florineflorio
F
15

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
Florineflorio answered 20/2, 2013 at 10:10 Comment(4)
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.Nominalism
@Nominalism 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.Eastbound
"const in C++ implies static... This seems like an arbitrary hack in C++ specification. Micro optimization for lazy people!!!Scandinavia
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.Cleaner
C
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

Cleaner answered 20/2, 2013 at 10:11 Comment(6)
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?Scandinavia
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.Cleaner
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.Scandinavia
@FooF: well, there are some subtleties for arrays and references... ;-)Cleaner
I am morbidly curious (it is quite a while since I programmed in C++)... Any links or explanations about the subtleties?Scandinavia
@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... :-)Cleaner
P
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";
Plainsman answered 3/1, 2022 at 20:22 Comment(2)
compiler will complain!Mako
Have not checked against the standard. See also https://mcmap.net/q/258836/-mixing-extern-and-constPlainsman

© 2022 - 2025 — McMap. All rights reserved.