Ok, this has got me banging my head against a wall. I have a structure defined in a header file. It get initialized in my "main.cpp" file, then later in a separate file "readconfig.cpp" it gets accessed to store information. I haven't been able to get it to compile except by using the following code, which segfaults. I was wondering if anyone here could assist me in this problem.

Here is the revelant main.h code:

#ifndef _MAIN_H
#define _MAIN_H
...
struct _aline { //Admin Line
std::string provider;
std::string serverdesc;
std::string admin;
};
...
#endif

main.cpp:

#include "main.h"
int main()
...
_aline *aline = new _aline;
aline->provider = "HURR DURR";
...

and readconfig.cpp:

bool ReadConfig()
...
_aline *aline;
cout<<"Aline: \n";
cout<<aline->provider<<"\n";
...

I've tried to get this code to compile, but so far this is the only way I can get it to. If I try to move the statement in readconfig.cpp to main.h I get linker errors like there's no tomorrow.

Any help is greatly appreciated.

Recommended Answers

All 10 Replies

Your problem looks like a lack of an extern + a scope error

Let me explain. You seem to "effectively" want to do this

int main()
{
   int var(10);          // this variable is local to main NOT the program
}

void foo()
{
   int a=var;         // THIS will not compile.
}

This is not allowed. That is because main(), as will all funcitons, protects its scope. So how to get round the problem:

int var;    // NOTE ABOVE MAIN

int main()
{  
   var=10;
}

void foo()
{
   int a=var;     // THIS is ok IF foo()'s defining is in the SAME file as main.
}

Well what if you want to have two separate files : For that we need the extern keyword.

// File Main
void foo();  // declaration 
int var;

int main()
{
   var =10;
   foo();
}
// SECOND FILE
extern int var;          // Note the extern keyword.

void foo()
{  
   int a=var;           // this is now ok and will get the value 10.
}

Hope that helps and question/comment please ask

commented: well said +31

Instead of making things global, why not make your function take in a _aline as a parameter?
For example ReadConfig(const _aline* line){ /* work with line variable */ }

And all you have to do is make sure that you can call ReadConfig from your file.

commented: I forgot that! +3

Yet another alternative.. maybe a bit of overkill or too advanced but if you want to implement this is the future again in a robust manner, you should know this thing you are probably trying to do here is called a "singleton", at least from reading between the lines of your original post. So a typically more robust solution that avoids global scope extern variables (which are pretty much not allowed on bigger projects):

// main.hpp
class Foo { .. };

Foo* getGlobalFoo();

// main.cpp

Foo* getGlobalFoo() {
  static Foo my_foo(.. some initial value ..);
  return &my_foo;
};

// other.cpp
#include <main.h>

void Bar() {
  Foo* global_foo = getGlobalFoo();
  ... use global_foo ...
};

I personally use a variation of that and it is really robust, never had any problems with it. There are advanced issues that probably out of scope of this thread that this scheme prevents better than the alternatives.

Thanks guys! I will try these!

Ok, I tried the class method and I'm having an issue. The code compiles fine, but I still segfault. I have the program setup to output the pointer addresses at specific points to debug. Here is what the code looks like:

main.h: (included by every .cpp file)

struct _mline { //Server Line
std::string hostname;
std::string description;
};

struct _aline { //Admin Line
std::string provider;
std::string serverdesc;
std::string admin;
};


class _db {
...
struct _aline aline;
struct _mline mline;
public:
...
_aline* get_aline();
_mline* get_mline();

void set_aline(std::string, std::string, std::string);
void set_mline(std::string, std::string);
};

static class _db *db;

main.cpp:

#include "main.h"
...
int main(int argc, char* argv[])
{
_db *db = new _db;
_aline *temp_aline;
temp_aline = db->get_aline();
std::cout<<"Before change Main: "<<temp_aline<<"\n";
db->set_aline("HURR DURR","","");
std::cout<<"Main Pointer: "<<temp_aline<<"\n";
...

readconfig.cpp

#include "main.h"
...
bool ReadConfig()
{
	_aline* a_line = db->get_aline();
	_mline* m_line = db->get_mline();
	cout<<"ReadConfig Pointer: "<<a_line<<"\n";
	cout<<"Aline: \n";
	cout<<a_line->provider<<"\n";
...

db.cpp (The get_aline and set_aline funcs):

_aline* _db::get_aline()
{
	std::cout<<"DB Aline: "<<&aline<<"\n";
	return &aline;
}

_mline* _db::get_mline()
{
	return &mline;
}

void _db::set_aline(std::string provider, std::string serverdesc, std::string admin)
{
	aline.provider = provider;
	aline.serverdesc = serverdesc;
	aline.admin = admin;
	return;
}

void _db::set_mline(std::string hostname, std::string description)
{
	mline.hostname = hostname;
	mline.description = description;
	return;
}

Here is the output:

brian@DC0:~/work/dev/sdirc$ ./sdircd -c sdirc.conf
DB Aline: 0x80690bc
Before change Main: 0x80690bc
Main Pointer: 0x80690bc
DB Aline: 0xb4
ReadConfig Pointer: 0xb4
Aline:
Segmentation fault

GDB Says:

Program received signal SIGSEGV, Segmentation fault.
0xb76e9745 in std::operator<< <char, std::char_traits<char>, std::allocator<char> > () from /usr/lib/libstdc++.so.6

So...I'm confused. I don't understand why the address changes between files. It doesn't change when you do stuff in the same file, it's like the compiler is making a new struct and trying to access it and failing. I would think the address would be the same, or close to it, if it was using the same struct as in main.cpp, but it's WAY off.

Any further help would be appreciated. Thanks for your help so far!

Ok, relax. First of all, you may think that the "_db* db" pointer that is initialized in main.cpp is the same as the "static _db* db;" declared in main.h. IT IS NOT! How scoping works is that the compiler tries to find the first variable named "db" in the inner-most scope first, so it will find a pointer "db" declared in the main() function and initialize that one, not the global one in "main.h". So when you get to readConfig() function, you are addressing a garbage point "db" that has not been initialized.

Simple solution: replace "_db *db = new _db;" with "db = new _db;" and it should work fine.

Another issue, make sure both cpp are compiled in the same translation unit. Otherwise you will have two different global "db" variables... and things will get messy. Remember one of my earlier posts where I suggest a static variable wrapped in a global function implemented in a unique cpp file. I said that was very robust and that I use it for many reasons.. you are starting to experience those reasons, by not following my suggested solution.

I followed your instructions, and they helped me fix the other problems. Thank you for all your help. I will use your solution in future projects. I implemented something close to it, using a function to get a global variable in a class.

I tried what you suggested, but I get the exact same results. Is there something else I am missing?

Thanks!

Read this through and you will understand it all.

commented: Very good link! +1

Now I understand! Great link! I get what you mean by "wrapping static variable into a function" now. The code compiles and runs as expected. Thank you!

What I changed:

main.h:

_aline& get_aline();

db.cpp:

_aline& _db::get_aline()
{
        static _aline* alinetoget = new _aline;
        std::cout<<"DB Aline: "<<&alinetoget<<"\n";
        return *alinetoget;
}

The rest was simple stuff, changing pointers to references and such.

Thank you!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.