rules of extern

J

John Ratliff

I have a few global variables in my app. They are defined in the main
application class file and declared (extern) in a header which can be
included by anyone who would want to use these variables.

Two of the globals are pointers which are initialized at runtime. The others
are classes whose values are initialized in the global space. When I had
just the pointers, I didn't need to include the extern header in the
defining class file. But now that I have the objects, I do. If I don't, ld
complains about undefined references.

Why is this?

It looks basically like this:

main.cpp

A *ptr;
B obj("string literal");

secondary.cpp

#include "externs.h"

void Secondary::method() {
cout << obj.toCharArr();
}

externs.h

class A;
class B;

extern A *ptr;
extern B obj;

Thanks,

--John Ratliff
 
H

Howard

John Ratliff said:
I have a few global variables in my app. They are defined in the main
application class file and declared (extern) in a header which can be
included by anyone who would want to use these variables.

Two of the globals are pointers which are initialized at runtime. The
others are classes whose values are initialized in the global space. When
I had just the pointers, I didn't need to include the extern header in the
defining class file.

I don't understand. What's "the defining class file"?
But now that I have the objects, I do. If I don't, ld complains about
undefined references.

Why is this?

Any unit which references a variable must be able to "see" that variable
somehow. Below, secondary.cpp contains code which references obj, so obj
must be defined somewhere visible to secondary.cpp, which is what including
externs.h does for it. This minimal example doesn't show ptr being used
anywhere, so naturally it won't require externs.h. Perhaps your real code
does have ptr referenced there somewhere, but if it does, it has to define
ptr _someplace_ which is visible to the code. But without the real code,
I'd only be guessing.
 
J

John Ratliff

Yeah, sorry for the not real code, but I can't seem to reduce the real code
to a small compilable problem. Let me try and rephrase.

In the file where the storage space for these globals is created, if I don't
also have the extern declarations, the linker will say my globals (the ones
that are not pointers) will say there are undefined references to these
variables. In other words, unless I have an extern declaration of these
variables (the ones that are not pointers), the linker will not export them
to the other modules. Yet, it exports the pointers with or without including
the extern declarations.

Is it a C++ requirement that I use an extern declaration if I want to export
these symbols? Are they limited to the module if I don't?

I guess maybe a better question might be, are variables declared at file
scope exported or not? Does the export require an extern declaration?

I read this in the C++ Faq Lite " (By the way, static data at file-scope is
now deprecated in C++: don't do that.) ". What does this mean? Is it saying
what I did was bad?

BidEuchreApp.cc (where storage space is defined for the globals)
------------------
#include "AppConstants.hh"

wxMutex *mutex;
wxCondition *cond;

const wxString APP_NAME(wxT(PACKAGE_NAME));
const wxString APP_VERSION(wxT(PACKAGE_VERSION));
const wxString APP_COPYRIGHT(wxT("Copyright (C) 2005 John David Ratliff"));
const wxString APP_URL(wxT("http://games.technoplaza.net/"));

BidEuchreApp::BidEuchreApp() {
mutex = new wxMutex();
cond = new wxCondition(*mutex);
}
------------------

AppConstants.hh
-------------------
class wxCondition;
class wxMutex;
class wxString;

extern const wxString APP_NAME;
extern const wxString APP_VERSION;
extern const wxString APP_COPYRIGHT;
extern const wxString APP_URL;
extern wxCondition *cond;
extern wxMutex *mutex;
---------------------------------

EuchreFrame.cc
-----------------------
#include "AppConstants.hh"

void EuchreFrame::helpAbout(wxCommandEvent& WXUNUSED(event)) {
wxString message = APP_NAME + wxT(' ') + APP_VERSION + wxT('\n') +
APP_COPYRIGHT + wxT('\n') + APP_URL;
wxString title = wxT("About ") + APP_NAME + wxT("...");

wxMessageBox(message, title, wxOK | wxICON_INFORMATION, this);
}
----------------------

Here is the actual code. I will post the entire compilable module if you
think it will help, but I have 30 some files and it requires wxWidgets 2.6
to compile. You can assume it does use cond and mutex somewhere, but not in
EuchreFrame.cc or BidEuchreApp.cc.

If you remove the include of AppConstants.hh in the BidEuchreApp.cc file,
you will get the following linker errors.

ui/EuchreFrame.o(.text+0x1266):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_VERSION'
ui/EuchreFrame.o(.text+0x12b8):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_COPYRIGHT'
ui/EuchreFrame.o(.text+0x130d):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_URL'
ui/EuchreFrame.o(.text+0x13b5):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:78:
undefined reference to `APP_NAME'
collect2: ld returned 1 exit status

The question is, why does the linker find the cond and mutex variables, but
not the APP_XXX variables?

Game.cc
----------------------
void Game::setPause(bool paused) {
this->paused = paused;
cond->Signal();
}
----------------------

Just one of the places cond is used, and ld has no problem with
BidEuchreApp.hh not including AppConstants.hh.

Thanks,

--John Ratliff
 
H

Howard

John Ratliff said:
Yeah, sorry for the not real code, but I can't seem to reduce the real
code to a small compilable problem. Let me try and rephrase.

In the file where the storage space for these globals is created, if I
don't also have the extern declarations, the linker will say my globals
(the ones that are not pointers) will say there are undefined references
to these variables. In other words, unless I have an extern declaration of
these variables (the ones that are not pointers), the linker will not
export them to the other modules. Yet, it exports the pointers with or
without including the extern declarations.

Is it a C++ requirement that I use an extern declaration if I want to
export these symbols? Are they limited to the module if I don't?

The extern specifier tells the compiler that the symbol is defined
elsewhere, and the reference must be resolved at link time.
I guess maybe a better question might be, are variables declared at file
scope exported or not? Does the export require an extern declaration?

You don't "export" the symbol. You simply declare it as exterrn in any unit
that needs to see it but doesn't wish to directly include the file it's
declared in. In your case, you declare it extern in a header, and include
the header wherever it's needed. That's the correct way.
I read this in the C++ Faq Lite " (By the way, static data at file-scope
is now deprecated in C++: don't do that.) ". What does this mean? Is it
saying what I did was bad?

I see nothing declared as "static" here.
BidEuchreApp.cc (where storage space is defined for the globals)
------------------
#include "AppConstants.hh"

wxMutex *mutex;
wxCondition *cond;

const wxString APP_NAME(wxT(PACKAGE_NAME));
const wxString APP_VERSION(wxT(PACKAGE_VERSION));
const wxString APP_COPYRIGHT(wxT("Copyright (C) 2005 John David
Ratliff"));
const wxString APP_URL(wxT("http://games.technoplaza.net/"));

Those are your declarations (and definitions of the wxString variables).
BidEuchreApp::BidEuchreApp() {
mutex = new wxMutex();
cond = new wxCondition(*mutex);
}

Fine, because cond and mutex are declared above.
------------------

AppConstants.hh
-------------------
class wxCondition;
class wxMutex;
class wxString;

extern const wxString APP_NAME;
extern const wxString APP_VERSION;
extern const wxString APP_COPYRIGHT;
extern const wxString APP_URL;
extern wxCondition *cond;
extern wxMutex *mutex;
---------------------------------

EuchreFrame.cc
-----------------------
#include "AppConstants.hh"

void EuchreFrame::helpAbout(wxCommandEvent& WXUNUSED(event)) {
wxString message = APP_NAME + wxT(' ') + APP_VERSION + wxT('\n') +
APP_COPYRIGHT + wxT('\n') + APP_URL;
wxString title = wxT("About ") + APP_NAME + wxT("...");

wxMessageBox(message, title, wxOK | wxICON_INFORMATION, this);
}
----------------------

Here is the actual code. I will post the entire compilable module if you
think it will help, but I have 30 some files and it requires wxWidgets 2.6
to compile. You can assume it does use cond and mutex somewhere, but not
in EuchreFrame.cc or BidEuchreApp.cc.

If you remove the include of AppConstants.hh in the BidEuchreApp.cc file,
you will get the following linker errors.

I must assume that you mean the problem occurs if you remove the include
from EuchreFrame.cc, since that's what the errors refer to. And
EuchreFrame.cc needs to tell the compiler where those symbols are defined.
It does so (in this case) by including the header file which declares them
as extern (thereby putting it on the linker to resolve the extern
declarations).
ui/EuchreFrame.o(.text+0x1266):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_VERSION'
ui/EuchreFrame.o(.text+0x12b8):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_COPYRIGHT'
ui/EuchreFrame.o(.text+0x130d):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:77:
undefined reference to `APP_URL'
ui/EuchreFrame.o(.text+0x13b5):C:/msys/1.0/home/jdratlif/bideuchre/source/ui/EuchreFrame.cc:78:
undefined reference to `APP_NAME'
collect2: ld returned 1 exit status

The question is, why does the linker find the cond and mutex variables,
but not the APP_XXX variables?

It doesn't. Look again. The pointers are never referenced in
EuchreFrame.cc, which is where the errors occur.
Game.cc
----------------------
void Game::setPause(bool paused) {
this->paused = paused;
cond->Signal();
}

You don't show what's included by Game.cc (or what's included by what it
includes...). So I can't tell where it's seeing cond from, but trust me,
it's included somehow.

You don't show any code from BidEuchreApp.hh, so I can't comment on that
one. My guess is that neither mutex nor cond are referenced in that file.
They are referenced in BidEuchreApp.cc, but that's where they are declared,
so there's no problem there.

I think you're just confusing EuchreFrame.cc and BidEuchreApp.cc here. It
doesn't matter if the variable is a pointer or any otther kind of object..it
must either be declared in the file, declared in an included file (or a file
included by a file that's included, etc.), or declared as extern (and then
actually defined elsewhere).

-Howard
 
J

John Ratliff

If you remove the include of AppConstants.hh in the BidEuchreApp.cc file,
I must assume that you mean the problem occurs if you remove the include
from EuchreFrame.cc, since that's what the errors refer to. And
EuchreFrame.cc needs to tell the compiler where those symbols are defined.
It does so (in this case) by including the header file which declares them
as extern (thereby putting it on the linker to resolve the extern
declarations).

No, this is not what I mean. I am really and truly referring to
BidEuchreApp.cc. It does not make sense to me either. EuchreFrame.cc has
AppConstants.hh included at the top, before it uses the globals. If it
did not, wouldn't I get a compiler error and be unable to reach the link
stage?

This doesn't seem right, but is it possible the rules are different for
global objects than global pointers (or other primitives)? Is it
possible objects are static by default, and primitives are extern?

It doesn't. Look again. The pointers are never referenced in
EuchreFrame.cc, which is where the errors occur.

Yes it does. They are used in Game.cc, and Game.cc produces no errors. I
can even remove the use of the APP_XX constants from EuchreFrame and the
include from BidEuchreApp.cc and Game.cc will still be able to use the
cond and mutex.
You don't show what's included by Game.cc (or what's included by what it
includes...). So I can't tell where it's seeing cond from, but trust me,
it's included somehow.

Game.cc includes AppConstants.hh. Sorry.
You don't show any code from BidEuchreApp.hh, so I can't comment on that
one. My guess is that neither mutex nor cond are referenced in that file.
They are referenced in BidEuchreApp.cc, but that's where they are declared,
so there's no problem there.

I meant BidEuchreApp.cc here. Apologies again. BidEuchreApp.hh is solely
a class def with no includes whatsoever.
I think you're just confusing EuchreFrame.cc and BidEuchreApp.cc here. It
doesn't matter if the variable is a pointer or any otther kind of object..it
must either be declared in the file, declared in an included file (or a file
included by a file that's included, etc.), or declared as extern (and then
actually defined elsewhere).

Thanks for all your time. I hope we're closer to solving this. Actually,
I don't care that I have to include the file in BidEuchreApp.cc where
they are defined. I just want to know why I do.

--John Ratliff


P.S. I don't know if it's helpful, but I posted the entire source at
http://www.technoplaza.net/temp/bideuchre-0.1.tar.bz2. Unless you have
wx 2.6, you won't be able to compile it though.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,677
Members
48,796
Latest member
Greg L.

Latest Threads

Top