C++ extern variable why can't I define it in main - c++

use.cpp
#include "my.h"
int main()
{
int foo = 7;
print_foo();
print(99);
}
my.h
#pragma once
extern int foo;
void print_foo();
void print(int i);
my.cpp
#include<iostream>
#include "my.h"
void print_foo()
{
std::cout << foo;
}
void print(int i)
{
std::cout << i;
}
So my question is pretty simple I declare an extern int foo in the header file then I DEFINE foo in main, why does this not work? If I don't define foo in main and define it outside of main in use.cpp then it works but when I define it in main() it doesn't. Why?

At global scope, the declaration
extern int foo;
declares a variable named foo that has external linkage, meaning that it might be defined in another translation unit.
At block scope (i.e., as a statement in the body of a function), the definition
int foo = 7;
has no linkage. That means that the compiler will never consider this foo to be the same entity as another foo from another scope. Therefore, this simply creates another variable that's unrelated to the global one, and does not initialize the global one.

Related

Using extern array in class method -> undefined reference

Can someone please explain me why
#include <iostream>
namespace helper1 {
void syncAPI();
};
void helper1::syncAPI() {
extern int *arrayOfIntPointers[];
std::cout << *arrayOfIntPointers[0] << std::endl;
}
int *arrayOfIntPointers[5];
int main()
{
int *newInt = new int;
*newInt = 1;
helper1::syncAPI();
}
results in this error
In function `helper1::syncAPI()': undefined reference to helper1::arrayOfIntPointers
instead of displaying '1'?
And why seems arrayOfIntPointers to be a member of helper1 ( helper1:: arrayOfIntPointers)?
EDIT: I want to access the global array from within the function syncAPI() because all necessary data will be stored there.
The declaration extern int *arrayOfIntPointers[]; is still inside the namespace, even though it's an extern declaration. So it declares helper1::arrayOfIntPointers.
The definition int *arrayOfIntPointers[5]; is outside a namespace, so it defines
arrayOfIntPointers in the "global" namespace - a different object.
To fix this, the extern declaration and the definition must match. Either define your arrayOfIntPointers inside your namespace or declare it outside the namespace. So you have two solutions:
Outside (preferred)
extern int *arrayOfIntPointers[];
void helper1::syncAPI()
{
...
}
Inside
namespace helper1
{
int *arrayOfIntPointers[5];
}
Because arrayOfIntPointers is not a member of namespace helper1 and the extern declaration within the function is most likely not what you want.

extern in namespace scope - gcc vs clang vs msvc

I've tested the seemingly strange code example below with the newest gcc, clang, and MSVC; both clang and gcc give link errors, but MSVC compiles and links without any problem. Which one is correct?
// foo.h
#pragma once
namespace A
{
class foo
{
public:
foo();
void print();
};
}
// foo.cpp
#include <iostream>
#include "foo.h"
int* p = nullptr;
using namespace A;
foo::foo()
{
p = new int(5);
}
void foo::print()
{
extern int* p;
std::cout << *p;
}
#include "foo.h"
int main()
{
A::foo f;
f.print();
}
gcc and clang:
foo.cpp:(.text+0x35): undefined reference to 'A::p'
Both GCC and Clang are standard compliant. The example and explanation are given in the standard [basic.namespace]/4:
The enclosing namespaces of a declaration are those namespaces in which the declaration lexically appears, except for a redeclaration of a namespace member outside its original namespace (e.g., a definition as specified in [namespace.memdef]). Such a redeclaration has the same enclosing namespaces as the original declaration.
[ Example:
namespace Q {
namespace V {
void f(); // enclosing namespaces are the global namespace, Q, and Q​::​V
class C { void m(); };
}
void V::f() { // enclosing namespaces are the global namespace, Q, and Q​::​V
extern void h(); // ... so this declares Q​::​V​::​h
}
void V::C::m() { // enclosing namespaces are the global namespace, Q, and Q​::​V
}
}
— end example]

change namespace variable value from outside (C++)

consider the following namespace:
// foo.h
namespace foo
{
extern int bar;
}
//foo.cpp
namespace foo
{
extern int bar = 42;
}
is there a way to change the value of bar somewhere else in the project (i.e, not inside the namespace)?
I mean something like:
// in some other .cpp file
#include foo.h
int setBar(int x)
{
foo::bar = x;
}
is there a way to change the value of bar somewhere else in the project (i.e, not inside the namespace)?
Yes, almost exactly as you've shown.
The only issue in your sample code is that you used extern in your foo.cpp file where you define your foo::bar variable. You need to remove extern from foo.cpp:
#include <iostream>
// foo.h
namespace foo
{
extern int bar; // use extern in header file to declare a variable
}
// foo.cpp
namespace foo
{
int bar = 42; // no extern in cpp file.
}
int setBar(int x)
{
std::cout << "old foo::bar: " << foo::bar << std::endl;
foo::bar = x;
std::cout << "new foo::bar: " << foo::bar << std::endl;
}
int main()
{
setBar(999);
}
Output:
old foo::bar: 42
new foo::bar: 999
If you declare a variable as extern, then you tell the compiler that he shall not define the variable in the current translation unit but rather let the linker look for a variable defined in another translation unit. Hence extern just declares a variable, but does not define it. Consequently, initialising a variable that has not beed defined makes no sense.
So you should actually write:
// foo.h
namespace foo
{
extern int bar; // Just declare...
}
//foo.cpp
namespace foo
{
int bar = 42; // Define and initialise
}
Note that you still provide a header file with extern int bar, which - when included by other translation units than foo.cpp - declare variable bar such that the code may refer to it even if it is defined in another library (e.g. in foo.o).

implementing or defining class or function declared inside an unnamed/anonymous namespace

Is it legal to define the implementation of a function or class members outside the unnamed (anonymous) namespace they've been defined inside.
My compiler accepts it but I want to be sure it's legal
e.g.
////////////////
// foo.cpp
namespace {
struct X
{
void foo(int x);
};
}
// Is this legal?
void X::foo(int x)
{
}
The reason is I would like to avoid the unnecessary indentation imposed by our uncrustify formatting
It is really no different than the following, which is totally legit:
namespace ns {
struct s {
void f();
};
}
using namespace ns;
void s::f() { }
The names from the named namespace are brought into the global namespace and thus definitions can be provided for them there. The only difference with the unnamed namespace is that it has no name (really, it has some unique, unutterable name) and the using namespace is implicit.
#include <iostream>
using namespace std;
namespace
{
struct X
{
X(int);
int x_;
};
}
X::X(int x) : x_(x) {}
int main()
{
X x(5);
cout << x.x_ << "\n";
return 0;
}
Compiles (and runs) under gcc 4.6.0
Yes. It's perfectly legal. The difference an unnamed namespace makes is that, the content of the namespace is available only within the file it's declared. If it's in .h file then, it will be added to all the subsequent .cpp file and every .cpp file will have a unique copy of the contents of the namespace.
In fact it's a better way to declare a global static variable. Now see, what kind of difference it will make:
namespace {
struct X
{
void foo(int x);
};
int i; // declare this global variable
}
If you put this code inside a header file then, wherever that header file is #includeed, all those .cpp file will have a different copy of int i; inside them. Changing the value of i in one .cpp file doesn't affect the other .cpp file.
Moreover, it will not give linker error for multiple definitions, since it's in unnamed namespace.
Edit: To evaluate it more, define the namespace as following:
// x.h
namespace
{
struct X
{
void foo(int x)
{
static int c; // static inside the function
cout<<"a = "<<(c++)<<endl;
}
};
}
Now #include this header file in 2 different .cpp files. In both of them try to call foo() with object of X. It will print:
a = 0
a = 0
Which means that X::foo() in both the .cpp files are different. If you give the namespace a name and repeat the same thing, it will output
a = 0
a = 1
Thus unnamed namespace creates a different copy for each translation unit.
It's legal in your scenario, but in one scenario, it will cause compiler ambiguous error.
In case have another class in X.h:
// X.h
struct X
{
void foo(int x) { }
};
And in foo.cpp, need to use the X defined in X.h
////////////////
// foo.cpp
#include "X.h"
namespace {
struct X
{
void foo(int x);
};
// use the X declared in anonymous namespace
void test()
{
X x;
x.foo(3);
}
}
// reference to 'X' is ambiguous
void X::foo(int x)
{
}
void otherFunction()
{
// Use struct X in X.h
::X x;
x.foo(3);
}
if leave the implementation code out of the anonymous namespace, compiler complains ambiguous. If move the implementation code inside anonymous namespace, it works fine.

How to declare a global variable that could be used in the entire program

I have a variable that I would like to use in all my classes without needing to pass it to the class constructor every time I would like to use it. How would I accomplish this in C++?
Thanks.
global.h
extern int myVar;
global.cpp
#include "global.h"
int myVar = 0; // initialize
class1.cpp
#include "global.h"
...
class2.cpp
#include "global.h"
...
class3.cpp
#include "global.h"
...
MyVar will be known and usable in every module as a global variable. You do not have to have global.cpp. You could initialize myVar in any of the class .cpp's but I think this is cleaner for larger programs.
While I would like to avoid global variables like the plague as our software cannot be multithreaded effectively due to the high reliance on global variables, I do have some suggestions:
Use a Singleton. It will allow you to keep the code and access clean. Part of the problem with a global variable is you don't know what code has modified it. You could set the value of global somewhere in your function relying on the hope that no one else will change it, but function your code calls, fooA, changes it and now your code is a) broken, and b) hard to debug.
If you have to use a global variable without touching the singleton pattern, look at fupsduck's response.
If you're not going to use the Singleton pattern as Lyndsey suggests, then at least use a global function (inside a namespace) to access the variable. This will give you more flexibily in how you manage that global entity.
// mymodule.h
namespace mynamespace // prevents polluting the global namespace
{
extern int getGlobalVariable();
}
// mymodule.cpp
namespace mynamespace
{
int myGlobalVariable = 42;
int getGlobalVariable()
{
return myGlobalVariable;
}
}
Just declare it outside the class:
Header file:
extern int x;
class A {
int z;
public:
A() : z(x++) {}
};
One source file:
int x = 0;
keyword extern
//file1.cpp
int x = 0;
//file1 continues and ends.
//file2.cpp
extern int x; //this gets tied into file1.cpp's x at link time.
//file2.cpp goes on and ends
Declare the variable as extern in a common header.
Define it in any source file.
// L.hpp
struct L { static int a; };
// L.cpp
int L::a(0);
The below solution should be simple enough as per the title "How to declare a global variable that could be used in the entire program
" .
If you want to use it in a different file then make use of extern keyword.
Please let me know if there is any issue with the solution
#include<iostream>
using namespace std;
int global = 5;
class base {
public:
int a;
float b;
base (int x) {
a = global;
cout << "base class value =" << a << endl;
}
};
class derived : public base {
public:
int c;
float d;
derived (float x, int y) : base (y)
{
d = global;
cout << "derived class value =" << d << endl;
}
};
int main ()
{
derived d(0,0);
cout << "main finished" << endl;
return 0;
}
if you want to declare it in different header files/cpp files, just declare it extern outside of other files
//file1.c
int x=1;
int f(){}
//file2.c
extern int x;