Difference between defining globally and within scope - c++

So, I have a variable declared globally. For it to be used, it has to be defined. I get different results based on whether I define it globally or within scope of the main function.
Here's the basic code:
// main.cpp
//int variable = 3;
int main()
{
//int variable = 5;
func();
return variable;
}
// source.cpp
#include "source.hpp"
void func()
{
cout << variable << endl;
}
// source.hpp
#ifndef __SOURCE_HPP_INCLUDED__
#define __SOURCE_HPP_INCLUDED__
#include<iostream>
using namespace std;
extern int variable;
void func();
#endif // __SOURCE_HPP_INCLUDED__
So, if I define globally (outside main), then everything works. But if I define within main, then I get "undefined reference to 'variable'" errors. But I only call upon source.cpp when I'm inside main; so why do I get this error, if variable is defined within the same "scope" as func? Is it the compiler just preemptively giving the error before linking is done? Or is it related to the fact that I declared it as "extern"?

You can't define a global variable inside a function. You're actually defining a different, unrelated local variable that just happens to have the same name.
func references the global variable, so you must have a definition for it.

Related

How to extern global smart pointers that are assigned within SetUpTestSuite?

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?

Static variables and different namespaces in c++

I have read on static variables and know what they are, how they function when define in a .cpp file, function, and class.
But I have slight confusion when define in different namespaces in the same cpp file.
One of these voted answers here says:
When you declare a variable as static inside a .h file (within or without namespace; doesn't matter), and include that header file in various .cpp files, the static variable becomes locally scoped to each of the .cpp files.
According to the program below, namespaces does matter.
static int a = 0;
namespace hello1 {
static int a = 1;
namespace hello2 { static int a = 2;}
namespace hello3 { static int a = 3;}
}
int main()
{
std::cout<<::a<<hello1::a<<hello1::hello2::a<<hello1::hello3::a;
return 0;
}
output
0123
Here is what I think: a outside namespaces is the file scope. a in hello1 is hello1 scope. Since hello1 is global scope namespace, I can only have one a in namespace hello1, including other cpp files where hello1 exists. The same goes for hello2 and hello3; only one a in each hello1::hello2 and hello1::hello3.
Please correct me If I understood it correct. The namespace does matter; static variables in the same cpp file under different namespaces are different entities.
That's not what the passage you quoted is talking about. It is referring to the fact that static variable names have internal-linkage. What that means is that you can't access a static variable a that is defined in "a.cpp" from "b.cpp", even if you include a declaration of a in "b.cpp". That declaration will refer to a different object.
For example:
A.hpp
static int a = 0;
void foo();
A.cpp
#include "A.hpp"
#include <iostream>
void foo() { std::cout << a << '\n'; }
B.cpp
#include "A.hpp"
#include <iostream>
int main() {
std::cout << a << '\n'; // prints 0
a = 1;
foo(); // prints 0, since it uses a different a
}
In this example, "A.cpp" and "B.cpp" see different global-scope objects named a since a was declared static. Even though main modifies a's value to be 1, foo still sees it as 0 since it's looking at a different a.
This behavior is irrespective of namespaces. If a were in a namespace other than the global namespace this same behavior would occur. That is what the passage you quoted is referring to.

Identification problem in variables belonging to extern storage class

a.cpp
extern int var;
int func(){
return var;
}
main.cpp
#include <iostream>
using namespace std;
extern int func();
int main(){
int var = 12;
cout << func();
}
When I write as above, I get this error "undefined reference to var".
a.cpp
extern int var;
int func(){
return var;
}
main.cpp
#include <iostream>
using namespace std;
extern int func();
int var = 12;
int main(){
cout << func();
}
But when I make the above change in the main.cpp file, the application compiles without any problems and 12 is printed on the screen.
Why does this problem occur?
Well, you never know if it's a troll, but in short, your first set of functions declare var as a local variable, within the scope of main() only. As such you may not reference it in a.cpp. Imagine if you did... the lifetime of var is (strictly) temporary (irrespective of being in the "main" function) and is not reserved in RAM, and as such the compiler will not allow the use of extern in a.cpp... what address could it use?
The second time you correctly declare var as a global, within main.cpp. As such your extern in a.cpp is valid, and you can thus reference var. In this case var is reserved in RAM, and accessible from files that declare it extern.
A good explanation of scope is available at tutorialspoint, and here at cplusplus.
In the first case, the variable is local to function main(). You cannot reference such local variables from other functions.
In the second case it is a global variable. That works.

Do inline namespace variables have internal linkage? If not, why does the code below work?

This question is directly related to this one. Consider the code:
#include <iostream>
inline namespace N1
{
int x = 42;
}
int x = 10;
int main()
{
extern int x;
std::cout << x; // displays 10
}
It displays 10. If I remove the extern int x; declaration then we get an ambiguity compiler time error
error: reference to 'x' is ambiguous
Question: why does the code work with the extern int x declaration work, and why does it stop working when I remove it? Is it because inline namespace variables have internal linkage?
No. There is no provision in [basic.link] that would cause x to have internal linkage. Specifically, "All other namespaces have external linkage.", and "other" refers to "not unnamed". Perhaps you were thinking of unnamed namespaces?
No, the code works because to avoid breaking existing C code, extern int x; has to work the same way in did in C, in other words creating a local extern to a global namespace (that's all we had in C) variable. Then when you use it later the locally declared extern removes any possible ambiguity.

Trying something simple with extern

I am trying to learn what "extern" does. I have a simple program where in main's header, a variable is declared with extern. In main, that variable is defined. Main then calls a method in another class file (that includes main's header so it should have access to the external variable), in order to print the value of that variable. But I get a compiler error: "unresolved external symbol "int myglobal". Can someone help? Thanks!
The code runs fine if I remove the reference to this variable in the source.cpp file.
source.cpp
#include "main.h"
#include <iostream>
void printGlobal()
{
std::cout << "Global: " << myglobal;
}
source.h
void printGlobal();
main.h
extern int myglobal;
main.cpp
#include "main.h"
#include "Source.h"
int main()
{
int myglobal = 5;
printGlobal();
system("pause");
return 0;
}
extern only works with global scope. if I say extern int myint; that means there is a file somewhere that has int myint; outside any function this is global scope
there is also file scope which is via static int myint; that means other files won't be able to access it via extern
change main.cpp to
#include "main.h"
#include "Source.h"
int myglobal = 5;
int main()
{
printGlobal();
system("pause");
return 0;
}
for file scope
#include "main.h"
#include "Source.h"
static int myglobal = 5;
int main()
{
printGlobal();
system("pause");
return 0;
}
extern and static keywords are storage specifiers. Each storage specifiers basically add two properties to a name:
1. Allocation or deallocation of name.
2. Visiblity.
If you add "extern" keyword to name in "C", it only declares a variable so that you can use that name in your program without compiler error. Means extern variable are visible outside the scope where they are defined. This symbol also instructs the linker to find the symbol definition in other object files. Therefore in your case when you added "extern" to myGlobal, you only declared a variable with name "myGlobal " and could use that name in your program. But when linker came, it tried to find the place where that "myGlobal" is defined, but it was unable to find this and gave you "unresolved external symbol" error.
All extern(global) variables are allocated when the program starts and destroyed when program ends.
Another use of "extern" other than what A.H. provided:
test1.c
int myextern = 10;
test2.c
void func1(){
int extern myextern;
printf("%d",myextern);
}
Static:
Allocation/Deallocation of static variables are same as extern variable. Means they are allocated when the program starts and destroyed when program finished. But visibility of the static variables are limited to the lexical scope where they are declared. They are not visible outside their scope.