I have driver.h which contains:
namespace org::lib{
extern bool masterBool;
}
And a library.h which contains an anonymous namespace that defines masterBool:
namespace {
bool masterBool = false;
std::string otherFunction(){
//....
}
}
My driver.cpp which calls the otherFunction() and masterBool:
#include driver.h
#include library.h
namespace org::lib{
void function(){
otherFunction();
if (masterBool){
//.....
}
}
}
Upon compiling, I'm getting a undefined symbol: org::lib::masterBool in my driver.cpp. However, otherFunction() call did not such an error, even though they are both defined in the anonymous namespace of library.h
What am I missing here?
::org::lib::masterBool is not the same variable as ::(unnamed)::masterBool and is never defined. (They wouldn't be the same even if the unnamed namespace appeared inside org::lib.) There aren't two otherFunctions (in any one translation unit—see below), so that problem can't occur there.
More generally, don't use unnamed namespaces in header files; even the rare recommendations are better served by inline variables (or some emulation of them prior to C++17).
Related
I have a couple global pointers defined in a UtTestBase.hpp which are to be used by the files that include it (e.g: UtTest1.cpp).
SetUpTestSuite() is static and thus performs a shared set up for all the tests. I view it as preconfiguration. Doing the way I have would complain about multiple definitions of the globals however using extern for each doesn't work either.
Using extern errors out
namespace TEST
{
extern std::weak_ptr<int> weakPtr;
extern std::shared_ptr<int> sharedInt;
// ...
}
// errors
undefined reference to `weakPtr' in line "weakPtr = sharedInt;"
undefined reference to `sharedInt' in line "sharedInt = std::make_shared<int>();"
From what I have seen the usage of extern involves declaring the variables in a header and defining in a respective source file that uses it
What's the way around? static inline is other option but does it make sense for each file to have a separate instance of a global given they are assigned in SetUpTestSuite()?
UtTestBase.hpp
namespace TEST
{
std::weak_ptr<int> weakPtr;
std::shared_ptr<int> sharedInt;
struct UtTestBase
{
static void SetUpTestSuite()
{
sharedInt = std::make_shared<int>();
weakPtr = sharedInt;
}
// .. some common methods
};
}
UtTestBase.cpp
#include "UtTestBase.hpp"
namespace TEST
{
TEST_F(UtTestBase, Test1)
{
// ...
}
}
UtTest1.cpp
#include "UtTestBase.hpp"
namespace TEST
{
struct UtTest1 : public UtTestBase
{
void SetUp() override
{
// do init for a local test
}
// should have sharedInt and weakPtr assigned
};
}
The reason for the compile error with extern is that this only references the global variable. One of the translation units (exactly one!) has to define it, too. So, in the header, you need it declared with extern, and in one(!) of the cpp files, it additionally needs to be defined without extern.
If you don't define the variable anywhere (and only reference it with extern), the linker will complain that the variable doesn't exist - that's the error messages you're getting.
Here's a simple example with an int.
Header:
//Declare that the variable exists, don't actually create it
extern int g_whatever;
CPP file 1:
#include "Header"
//Create (define) the variable
int g_whatever;
CPP file 2, 3, ...:
#include "Header"
//Use g_whatever, *without* defining it again
This is independent of where you actually initialize the global variable. You could put the definition into UtTestBase.cpp, for example.
For a more in-depth explanation, see: How do I use extern to share variables between source files?
I have an header file that i put some global const variables. Now I need another project wide modifiable variable. But it gives linker error as expected. I am trying to solve the issue without using inline keyword. My codes:
constants.h:
#ifndef CONSTANTS_H
#define CONSTANTS_H
namespace constants {
bool myVar;
}
#endif // CONSTANTS_H
I am using this variable in my classes with constants::myVar. And I got a linker error. Any solution without using inline (for backward compiler compability)?
I completely agree with the comments above about looking at alternatives for this design.
Also as you seems to be aware, c++17 inline variables offer a better solution.
Having said that, if you must keep the current design - you can do the following:
Change the header file to declare myVar as extern:
namespace constants {
//--vvvvvv------------
extern bool myVar;
}
Add constants.cpp file (if it doesn't exists yet), with a definition for myVar (preferably with some initialization):
namespace constants {
bool myVar;
// or better: something like:
bool myVar = false;
}
1) I know a non-const variable is external linkage by default (it's like it's been declared as external more or less) but i don't understand why can't i define a global variable such as int glbl_a in header
//test.h
#ifndef TEST_H
#define TEST_H
int glbl_a=0; //wrong -> "multiple definition of `glbl_a`"
static int st_glbl_a=1; //ok to initialize it in header!
extern int ext_glbl_a; //ok to declare it and define it in test.cpp
#endif
//test.cpp
#include "test.h"
using namespace std;
//st_glbl_a=22; i could use st_glbl_a but it wouldn't affect st_glbl_a in main cause of 'static'
int ext_glbl_a=2; //definition of external gloabal non-const variable
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
extern int glbl_a; //declaration of glbl_a external
int main(){
cout<<glbl_a;
}
the working version for this program is the one in which I define int glbl_a=0; in test.cpp only and declare extern int glbl_a; in main before using it in output (definition in test.h is just commented, that is there's nothing about glbl_a).
2)the working version doesn't work anymore if I group all definitions/declaretions into a namespace spread onto test.cpp and test.h (MyNamespace) cause of int glbl_a in test.cpp:
//test.h
#ifndef TEST_H
#define TEST_H
namespace MyNamespace{
//extern int glbl_a;
}
#endif
//test.cpp
#include "test.h"
using namespace std;
namespace MyNamespace{
int glbl_a=0;
}
//main.cpp
#include <iostream>
#include "test.h"
using namespace std;
int main(){
cout<<MyNamespace::glbl_a; //wrong -> "'glbl_a' is not a member of 'MyNaspace'"
}
it would work only if I de-comment declaration in test.h, but why?
Problem 1
Including a header effectively pastes the included file into the including file, producing one large file that is then compiled (and, typically, promptly deleted). This means that every including file now has its very own glbl_a. The compiler is happy, but when the linker attempts to put everything together, it finds many equally valid pretenders to the name glbl_a. The linker hates this and doesn't even try to figure out what you're trying to do. It simply spits out an error message and asks that you fix the problem.
Problem 2
test.cpp and main.cpp are different translation units. They compile to produce different, completely independent objects. Neither can see what's in the other, so the fact that MyNamespace::glbl_a exists in test.cpp is lost on main.cpp. When main.cpp is compiled, the compiler builds a list of identifiers declared in the file constructed from main.cpp and all of its included headers. MyNamespace::glbl_ais never declared as of when it is first used (or after for that matter) so the compiler spits out an error message.
Uncommenting the declaration in test.h means the compiler will find MyNamespace::glbl_a in main.cpp and will allow it's use. Since MyNamespace::glbl_a is defined in test.cpp the linker can find one-and-only-one MyNamespace::glbl_a and can successfully link.
extern does not allocate storage. Instead it is a promise to the compiler that the variable being declared will be fully defined and allocated somewhere else, maybe later in the file or in another file. The variable exists, somewhere, and compilation can continue. The linker will call you out as a liar if it cannot find a definition.
More details here: How does the compilation/linking process work?
More on extern: When to use extern in C++ and Storage class specifiers
headers will be included by other files (more than one) thus if you define in header, it will be in each translation unit thus lead to "multiple definition"
I'm trying to make a namespace and its members available globally however I am running into already defined errors.
Settings.h
#pragma once
#include "boost/property_tree/json_parser.hpp"
#include <string>
using json = boost::property_tree::ptree;
namespace Settings {
extern std::string settingsPath;
extern json settings;
extern void init();
extern void readSettings();
extern void writeSettings();
};
Settings.cpp
#pragma once
#include "Settings.h"
using json = boost::property_tree::ptree;
namespace Settings {
void init() {
}
void readSettings() {
}
void writeSettings() {
}
};
I am forward declaring the Settings namespace and members and using extern. I have no idea what I'm doing wrong. Please could someone point out the error here.
Thanks
Edit: The actual error messages:
Error LNK2005 "class std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> > Settings::settingsPath" (?settingsPath#Settings##3V?$
basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##A) already defined in
AmalgamService.obj Amalgam F:\Dropbox\CPP\Visual Studio Projects\Amalgam\Amalgam\
main.obj 1
And repeat for all members of the namespace. The Settings.h is #includeed in main.cpp and AmalgamService.cpp
You seem to be including Settings.cpp in another file. Do not include .cpp files. This results in duplicate definitions. This also means that #pragma once in .cpp files is useless.
You need to keep in mind that #include is just a glorified copy&paste tool. When you #include a file, that file is literally being copy&pasted into the spot of the #include statement. So including a .cpp file means you will get multiple definitions of everything defined in that .cpp file.
Furthermore, you don't have to use extern when declaring functions. Functions are extern by default, unless you say otherwise.
Variables are extern by default too, however you need to use extern as a way to declare them without defining them:
extern int var; // declaration
int var; // definition
Functions don't need that, because you can declare them by omitting their body:
void func(); // declaration
void func() { } // definition
You are allowed to declare things multiple times, which is why you can #include header files (like .h, .hpp) in multiple files. But you are not allowed to define things multiple times, which is why you can't #include non-header source files.
I want to use extern keyword for user defined types. This means I've declared object in one file and defined it in other file. I've read that extern keyword is used to declare the variable without defining it. extern keyword is useful when program is split into multiple source files and global variable needs to be used by each of them. Please correct me If I am wrong somewhere.
Here is the programs I've written but unfortunately I am doing something wrong or missing something so I am getting compiler errors.
Prog1.cpp
#include <iostream>
using std::cout;
class test
{
public:
void fun();
};
void test::fun()
{
cout<<"fun() in test\n";
}
test t;
Prog2.cpp
#include <iostream>
using std::cout;
extern test t;
int main()
{
t.fun();
}
Now when I compile these 2 using
g++ -o prog1.cpp prog2.cpp
compiler gives me following errors in prog2.cpp
error: 'test' does not name a type
error: 't' was not declared in this scope
Please help me to know what I've done wrong here.
extern tells the compiler that the definition of t is somewhere else, but the compiler still needs the defintiion of test, as you're using t.fun() to compile Prog2.cpp.
So the solution is, write test.h where you define the class, and then define test t in Prog2.cpp as usual. Include test.h in your Prog2.cpp so that it may know the definition of test. Then build it.
test.h:
#include <iostream>
using std::cout;
class test //definition of test
{
public:
void fun()
{
cout<<"fun() in test\n";
}
};
Prog1.cpp:
#include "test.h"
test t; //definition of t
Prog2.cpp:
#include <iostream>
#include "test.h"
using std::cout;
extern test t; //the definition of t is somewhere else (in some .o)
//and the definition of test is in test.h
int main()
{
t.fun();
}
Now your code should compile and link.
Note that the definition of t is needed by the linker at link-time, so it will search for it in other .o files, but the definition of test is needed by the compiler, at compile-time.
Now it should be obvious that you can put the extern test t; in the header itself so that you dont have to write it in every .cpp file where you want to use the object defined in Prog1.cpp file (which is turned into Prog1.o by the compiler).
Put the extern keyword in the header, not the cpp file. It is the job of the header to tell the compiler there is an externally defined object somewhere.
For example:
program.h (mostly declarations)
struct UserDefinedType
{
void do_stuff();
};
// declare your global object in the header
// so that the compiler knows its name when
// compiling sources that can not otherwise see
// the object
extern UserDefinedType global_udt;
program.cpp (mostly definitions)
#include "program.h"
// define the member functions here
void UserDefinedType::do_stuff()
{
}
// define the global object here
UserDefinedType global_udt;
main.cpp (use the definitions that have been declared in the header)
#include "program.h" // tells the compiler about global_udt
int main()
{
// call the global object that is defined
// in a different source file (program.cpp)
global_udt.do_stuff();
}
NOTE: If we didn't declare the object global_udt in the header file then main.cpp would not know of its existence and the compiler would complain if we tried to use it.
So the header needs to only declare the object and not define it hence the extern keyword is needed.
Please note that a variable declared outside the class scope is a variable with external linkage(if not explicitly used the static keyword) or with internal linkage(if the static keyword is put in the left of the variable type), extern is necessary if you want to use it in multiple files.
Suppose this file is called MyVariable.h
int myNumber = 0; // Initialization of the variable myNumber, external linkage
static int myStaticNumber; // Initialization of the variable myStaticNumber, internal linkage(only the file in which it's declared)
And this file is OtherFile.cpp
extern int myNumber; // Not a initialization because it's already initialized in another file, works fine
extern int myStaticNumber; // ERROR, this variable has internal linkage!!
You may wonder why myStaticNumber was initialized and not just declared, that occurs because static variables are initialized to their default values by default.