Re: How to avoid multiple definitions of global variable
On 25 Jun, 08:54, Joacim Thomassen <joa...@olex.no> wrote:
Hi.
I need some help with my understanding of code structures and scopes. g++
tells me that a namespace-global variable (ABC::a) either has "multiple
definitions" or is "not used" if I change the type to static. Either way
I don't understand why?
1. Why do I have to make it static?
You don't. Your problem stems from the fact that you define (not just
declare) ABC::a in every translation unit that includes fil1.hpp; the
One Definition Rule forbids this, so you get the "multiple definition"
diagnostics. [A "translation unit" (TU) is, roughly, defined as all
the source code that gets compiled to create a single object file -
usually a single source file and all the files it #includes, and all
the files that they #include, etc.]
2. If static is the answer why do g++ complain saying ABC::a "not used"?
When you declare (and define) ABC::a with the "static" keyword, you limit
the scope of visibility of that definition to the translation unit being
compiled. This means that each translation unit again defines its own
object named ABC::a but their names don't "leak out" to the linker, so no
multiple-definition errors occur. However, you do have multiple objects
and the one used in one TU will be a completely different object to that
used in another TU. This can result in unexpected behaviour, although
your encapsulation of the set_a()/get_a() accessor code into a single
translation unit has saved you from such behaviour here.
As I run the program ABC::a appears to be used with the correct and
intended values.
This program illustrates my problem:
This program does not compile. Please, in future, copy-and-paste your
code directly into your postings.
fil1.hpp
#ifndef FIL1_HPP
#define FIL1_HPP
namespace ABC {
bool a = 0;
Here is your multiple-definition problem. This header gets included in
several source files and each one defines this variable when it encounters
this line. You only want to declare its existence, here. Change it to...
extern bool a;
void set_a(bool val);
bool get_a();}
#endif
fil1.cpp
#include "fil1.hpp"
Your ABC::a object must be defined once (and only once) somewhere in
your
program, and here is the logical place to do it...
bool ABC::a = false;
void ABC::set_a(bool val) { ABC::a = val; }
bool ABC::get_a() { return ABC::a }
___________________________________^
missing semicolon
fil2.hpp
#ifndef FIL2_HPP
#define FIL2_HPP
class ClassA {
public:
ClassA();};
class ClassB {
public:
bool g();};
#endif
fil2.cpp
#include "fil2.hpp"
#include "fil1.hpp"
#include <iostream>
ClassA::ClassA() { Abc::set_a(true); }
_____________________^^^
no class or namespace named "Abc" has been declared
(I assume you meant "ABC" here)
int main(int argc, char *argv[]) {
ClassB objB;
std::cout << objB.g() << "\n";
ClassA objA;
std::cout << objB.g() << "\n";
}
fil3.cpp
#include "fil2.hpp"
#include "fil1.hpp"
bool ClassB::g() { return Abc::get_a(); }
____________________________^^^
no class or namespace named "Abc" has been declared
(I assume you meant "ABC" here)
Compiling the code gives this output from g++:
g++ -o fil2 fil2.cpp fil3.cpp fil1.cpp
/tmp/ccj0QGrI.o:(.bss+0x0): multiple definition of `ABC::a'
/tmp/ccYUSmEL.o:(.bss+0x0): first defined here
/tmp/cceKUTkJ.o:(.bss+0x0): multiple definition of `ABC::a'
/tmp/ccYUSmEL.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [all] Error 1
The compiling and linking is successful as soon as I change the
declaration in file1.hpp like this:
- bool a = 0;
+ static bool a = 0;
BUT 'g++ -Wall' gives this warning:
g++ -Wall -o fil2 fil2.cpp fil3.cpp fil1.cpp
fil1.hpp: At global scope:
fil1.hpp:5: warning: 'ABC::a' defined but not used
fil1.hpp:5: warning: 'ABC::a' defined but not used
Why?
Because each source file includes that line declaring a static object
(visible only to the code that source file) and you don't reference it
in some of those translation units.
This is disturbing as my program appears to do the right thing anyway.
True, as you only use ABC::set_a() and ABC::get_a() to access ABC::a.
If you tried accessing it directly from the differenct source files
you
could see strange results.
Running fil2 gives this stdout:
0
1
As expected. Only the [fil1.cpp]::ABC::a object is ever accessed (by
ABC::set_a() and ABC::get_a() in fil1.cpp). Those "ABC::a" objects
defined in the other source files are never accessed (as your compiler
helpfully tells you.)
I know static will give the program only one occurrence of 'a' in memory.
No, this is wrong. "static" will give /each translation unit/ its own
private object named 'ABC::a' which is inaccessible to code in other TUs.
I don't understand why and how my program result in multiple definitions
of ABC::a as I declar ABC::a non-static. The #ifndef check should protect
me from multiple #includes messing things up?
Your problem has nothing to do with multiple includes.
Is there something fundamental regarding namespace and scope I've missed?
Your problem has nothing to do with namespaces (you could remove all the
ABC/Abc names from your code and it would still exhibit the same problem.)
Your (lack of) understanding of the use of "static" at namespace/global scope
seems to be the problem, perhaps along with the difference between
declarations and definitions at this scope.
Please let me know what I'm looking for and where I can find some answers.
Hopefully, you've just been furnished with them.
Cheers,
Tony.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]