Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Linking extern variables from within a namespace

I can't seem to reference an externally-defined variable from within a namespace using extern. It works from the global scope, but as soon as a namespace is thrown in there, it fails to link.

My constants file looks like:

StringConstants.cpp

#include "MyString.h"

MyString test1("string1");

MyString test2("string2");

The main program looks like this:

main.cpp

#include <stdio.h>
#include "MyString.h"

extern MyString test1;

namespace {
    extern MyString test2;
}

int main(void) {
    printf("%s\n", test1.Str());
    printf("%s\n", test2.Str());
}

I get similar errors in both GCC and Visual Studio:

gcc    main.o StringConstants.o   -o main
main.o:main.cpp:(.text+0x49): undefined reference to `(anonymous namespace)::test2'
collect2: ld returned 1 exit status

1>Linking...
1>main.obj : error LNK2001: unresolved external symbol "class MyString `anonymous namespace'::test2" (?test2@?A0x0df4aa01@@3VMyString@@A)
1>C:\p4\namespace_repro\namespace_repro2\Debug\namespace_repro2.exe : fatal error LNK1120: 1 unresolved externals

I tried qualifying the reference to test2 (extern MyString ::test2), but it just thinks that test2 is a static member of MyString. A named namespace doesn't behave differently than an anonymous one. For various reasons, we don't want to remove namespaces or put the externs outside of the namespaces.

Here's the other files, for completeness:

MyString.h

class MyString {
public:
   MyString(const char* str): mStr(str) {};
   const char* Str() const { return mStr; }
private:
   const char* mStr; 
};

Makefile

CC=gcc 
CFLAGS=-Wall

main: StringConstants.o main.o

The goals for this system are that the constants all be defined in one file, and that they be resolved at link time rather than being in a header. It seemed like the above code would work, but since it's rejected by two different linkers it seems my understanding of C++ is not good enough. Advice on how to get this to work, other than putting the externs outside of the namespaces?

like image 702
breath Avatar asked Jan 22 '23 02:01

breath


1 Answers

What...

namespace { 
    extern MyString test2; 
} 

...does is say test2 should exist in an anonymous namespace, but it doesn't - it's in the global namespace. You've lied to your compiler, therefore it generates an object that won't link. You need the extern declaration to be made from the same namespace scope as the variable.

BUT, there should be a StringConstants.h, which main.cpp should include, such that the compilation unit knows about the strings without any further statements.

like image 183
Tony Delroy Avatar answered Jan 29 '23 10:01

Tony Delroy