From: Joacim Thomassen on
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?
2. If static is the answer why do g++ complain saying ABC::a "not used"?
As I run the program ABC::a appears to be used with the correct and
intended values.

This program illustrates my problem:

fil1.hpp
#ifndef FIL1_HPP
#define FIL1_HPP
namespace ABC {
bool a = 0;
void set_a(bool val);
bool get_a();
}
#endif

fil1.cpp
#include "fil1.hpp"
void ABC::set_a(bool val) { ABC::a = val; }
bool ABC::get_a() { return ABC::a }

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); }
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(); }

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? This is disturbing as my program appears to do the right thing
anyway.

Running fil2 gives this stdout:
0
1

I know static will give the program only one occurrence of 'a' in memory.
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? Is there something
fundamental regarding namespace and scope I've missed? Please let me know
what I'm looking for and where I can find some answers.

Joacim Thomassen


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Richter on
Joacim Thomassen schrieb:
> 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?

You must only define it once, but you may declare it many times.

> 1. Why do I have to make it static?

I don't think you have to.

> 2. If static is the answer why do g++ complain saying ABC::a "not
> used"?

Because there is a copy of ABC::a (actually multiple) that are not used.

> As I run the program ABC::a appears to be used with the correct and
> intended values.
>
> This program illustrates my problem:
>
> fil1.hpp
> #ifndef FIL1_HPP
> #define FIL1_HPP
> namespace ABC {
> bool a = 0;
> void set_a(bool val);
> bool get_a();
> }
> #endif

This breaks the one-definition-rule. If you include this file from
multiple sources, ABC::a will be defined multiple times.

Instead, declare it in the hpp file:

namespace ABC {
extern bool a;
extern void set_a(bool val);
extern bool get_a();
}

and, within fil1.cpp, you define it by writing:

namespace ABC {
bool a = 0;
}

> I know static will give the program only one occurrence of 'a' in
> memory.

I afraid I believe wrong. "static" limits the visibility of a, but if
you define a multiple times, you will have multiple copies of it. They
do not conflict because the definition in one compilation unit is not
visible in another.

> I don't understand why and how my program result in multiple
> definitions
> of ABC::a as I declar ABC::a non-static.

Because you define it multiple times. (-:

> The #ifndef check should protect
> me from multiple #includes messing things up?

The define is not kept during multiple compiler runs. If you compile
"file1.c" which includes fil1.hpp, and then run the compiler again on
"file2.c", which also includes fil1.hpp, you'll have two definitions of
ABC::a.

So long,
Thomas

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Thomas Maeder on
Joacim Thomassen <joacim(a)olex.no> writes:

> 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?

fill.hpp contains a's definition; if fil1.hpp is #included by more
than one translation unit (.cpp file) of a program, then that program
contains multiple definitions.


> 1. Why do I have to make it static?

You don't. And normally you shouldn't.

Declaring it static will cause each translation unit to have a
separate variable a, unrelated to the as of the other translation
units.

NB: if you find this hard to read (I did when reading it through),
then because a is a very clumsy variable name. :-)


> 2. If static is the answer why do g++ complain saying ABC::a "not used"?
> As I run the program ABC::a appears to be used with the correct and
> intended values.

No answer here, the premise isn't true.


The real solution (from a language point of view; see below) is to
declare (but not define) a in the header, and to define it in just one
translation unit (the one that also defines set_a() and get_a()).


> This program illustrates my problem:
>
> fil1.hpp
> #ifndef FIL1_HPP
> #define FIL1_HPP
> namespace ABC {
> bool a = 0;

Change this to

extern bool a;

BTW: why didn't you use false to initialize a?


> void set_a(bool val);
> bool get_a();
> }
> #endif


> fil1.cpp
> #include "fil1.hpp"

Add

namespace ABC
{
bool a = false;
}

here.


> void ABC::set_a(bool val) { ABC::a = val; }
> bool ABC::get_a() { return ABC::a }

NB: no qualification of a is required in functions belonging to the
same namespace. E.g.:

void ABC::set_a(bool val)
{
a = val;
}


I wrote "from a language point of view" above, because from a design
point of view, it's better to remove a from the header
altogether. Anybody accessing a can use get_a() or set_a(), right?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Martin T. on
Joacim Thomassen 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?
> 2. If static is the answer why do g++ complain saying ABC::a "not used"?
> As I run the program ABC::a appears to be used with the correct and
> intended values.
>
> This program illustrates my problem:
>
> fil1.hpp
> #ifndef FIL1_HPP
> #define FIL1_HPP
> namespace ABC {
> bool a = 0;
> void set_a(bool val);
> bool get_a();
> }
> #endif
>

You are declaring two functions here but you are declaring _and_
defining the variable. If you only want to access the variable through
your functions, the you should put the definition of the variable in the
cpp file, i.e. change
> fil1.cpp
> #include "fil1.hpp"
> void ABC::set_a(bool val) { ABC::a = val; }
> bool ABC::get_a() { return ABC::a }
>
to
fil1.cpp
#include "fil1.hpp"
namespace ABC {
bool a = 0;
void set_a(bool val) { a = val; }
bool get_a() { return a }
};

If you want the variable to be declared in the header, you have to use
the 'extern' keyword.

br,
Martin

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Martin Bonner on
On Jun 25, 8:54 am, Joacim Thomassen <joa...(a)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?
> 2. If static is the answer why do g++ complain saying ABC::a "not used"?
> As I run the program ABC::a appears to be used with the correct and
> intended values.
>
> This program illustrates my problem:
I have shrunk the code:
>
> fil1.hpp
> #ifndef FIL1_HPP
> #define FIL1_HPP
> namespace ABC {
> bool a = 0;
> }
>
> #endif
>
> fil1.cpp
> #include "fil1.hpp"
... use ABC::a

> fil2.cpp
> #include "fil1.hpp"
... also use ABC::a

The problem is that fil1.hpp DEFINES ABC::a. You need to make sure
that it only DECLARES it. Change the header file to:

extern bool a;
(which is just a declaration).
And then, in file1.hpp, add the following line to define the variable:

bool ABC::a = false;

That will fix everything.
> I know static will give the program only one occurrence of 'a' in memory.
No, no, no! If you put "static" in the header file, there will be
*three* separate occurences of 'a' - one for each of the files where
you #include "fil1.hpp". That is why gcc complains. In fil2.cpp and
fil3.cpp you don't use the copy you have added.

In fact, in this /particular/ case, the correct thing to do, is to
remove the declaration of 'a' from the header file completely (it is
only used in fil1.cpp, and nobody else needs it). You can then
declare (and define) it as static in fil1.cpp (or put it in the
unnamed namespace).

Note: Your current code (with static) will work; you just waste some
space. But as soon as you make get_a inline, it will stop working!
> 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? Is there something
> fundamental regarding namespace and scope I've missed? Please let me know
> what I'm looking for and where I can find some answers.

{ Signature and clc++m banner removed; please, please, don't quote them,
as you're not replying to them. -mod }

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]