Register | Login
Views: 19364387
Main | Memberlist | Active users | ACS | Commons | Calendar | Online users
Ranks | FAQ | Color Chart | Photo album | IRC Chat
11-02-05 12:59 PM
0 user currently in Programming. | 3 guests
Acmlm's Board - I2 Archive - Programming - C++: Bizarre Multiple Declarations | |
Add to favorites | "RSS" Feed | Next newer thread | Next older thread
User Post
beneficii

Lakitu
Level: 36

Posts: 384/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 10:31 AM Link | Quote
Alright, I'm working on a project in C++ that has multiple source files with the same header file between them. Any variable I declare specific to a source file I declare as static (i.e. that is only for that source file) and any variable that is shared between source files is declared in the header file (not as static) I would think that most here would agree that this is standard practice in really big projects.

Now, I've tried compiling my project, I've gone through and corrected all syntax editors and it looks like I'm finally going to get it to compile when BAM! a very looooong list of linker errors shows up. They all said:

multiple definition of 'variable'
first defined here

(I'm using Bloodshed Dev C++ v. 4.9.9.2 btw and its default compiler GNU C++ Compiler.)

After that, I look at those variables and I see that they are all declared in the header file! I go to the compile log and see basically this:

sourcefileB.cpp: multiple definition of 'variableJ' // again variableJ is declared only in the header file
sourcefileA.cpp: first defined here
sourcefileC.cpp: multiple definition of 'variableJ'
sourcefileA.cpp: first defined here
sourcefileD.cpp: multiple definition of 'variableJ'
sourcefileA.cpp: first defined here

I'm thinking, okay, why is there a conflict here? Doesn't the linker know that these variables were all declared in a header file that was simply used by all the source files? I wrote a much smaller program afterward with two source files and a header file, which was included in both source files. I declared some variables in the header file. When it compiled, there was no conflict and the program ran normally. I'm wondering, What makes my program so different? Is it a problem with the compiler, or is there perhaps a common trap that I'm falling for?

Can any of you perhaps help me? Thanks.
neotransotaku

Baby Mario
戻れたら、
誰も気が付く
Level: 87

Posts: 3767/4016
EXP: 6220548
For next: 172226

Since: 03-15-04
From: Outside of Time/Space

Since last post: 11 hours
Last activity: 1 hour
Posted on 08-06-05 11:08 AM Link | Quote
try placing this as the first two lines of the shared header file

#ifdef __headerfile
#define __headerfile

and this as the end of the shared header file

#endif


usually this is the techinique to ensure a header file is included only once
beneficii

Lakitu
Level: 36

Posts: 386/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 11:34 AM Link | Quote
Originally posted by neotransotaku
try placing this as the first two lines of the shared header file

#ifdef __headerfile
#define __headerfile

and this as the end of the shared header file

#endif


usually this is the techinique to ensure a header file is included only once


Hold on.

Nope, if I do it #ifdef __headerfile, then __headerfile will never get defined. I tested it out anyway, and when I compiled the program it said that none of the variables defined in the header file were defined. I next tried #ifndef __headerfile, which seemed more logical, but still had the problem of multiple declarations. I counted the same number of underscores and everything. I wonder what's wrong.


(edited by beneficii on 08-06-05 02:37 AM)
(edited by beneficii on 08-06-05 02:43 AM)
HyperLamer
<||bass> and this was the soloution i thought of that was guarinteed to piss off the greatest amount of people

Sesshomaru
Tamaranian

Level: 118

Posts: 6326/8210
EXP: 18171887
For next: 211027

Since: 03-15-04
From: Canada, w00t!
LOL FAD

Since last post: 2 hours
Last activity: 2 hours
Posted on 08-06-05 02:26 PM Link | Quote
Yeah, #ifndef, not #ifdef. That should do it.

Are these source files all part of the same project, though? If they are, you should only need to include the header once, not in each file.
neotransotaku

Baby Mario
戻れたら、
誰も気が付く
Level: 87

Posts: 3770/4016
EXP: 6220548
For next: 172226

Since: 03-15-04
From: Outside of Time/Space

Since last post: 11 hours
Last activity: 1 hour
Posted on 08-06-05 07:40 PM Link | Quote
yeah, i mean't #ifndef

as for issues of multiple declarations, the only thing I can think of is how exactly you are organizing your files...
Dish

Spiny
Level: 38

Posts: 500/596
EXP: 355646
For next: 14801

Since: 03-15-04
From: Disch

Since last post: 18 days
Last activity: 18 days
Posted on 08-06-05 08:23 PM Link | Quote
If you define a variable to be global, it will have global scope (Global meaning it exists for the whole program). If you #include a header file which has a var declaration in several .cpp files, each .cpp file will create its own variable with the same name. This is where your problems are coming from.

The solution here is to make the variable once, then link it so that all .cpp files have access to it.


int myVar; /* will actually make the variable -- only have 1 of these */

extern int myVar; /* will not make the variable, will link to it after compile time -- have one of these for each .cpp file beyond the first */


Of course extern int myVar will only work if 'int myVar' is declared somewhere in your program.

For a halfway decent analogy of why it works this way... making the actual variable (int myVar) actaully makes the variable with a "body". Similar to how making a function with a body gives the function it's body. If you have a function in your program which has several bodies, you'll get errors much like the ones you were getting -- because you were making several different variables which have the same body -- and the compiler doesn't know which one you want to use.

Making it 'extern' says "okay, this variable exists... but not in this .cpp file, so we'll link to it, but it won't be in this compile" -- which is kind of like a body-less variable. Equivilent to having a function prototype (function without a body). It's making the function/var available for use, but without actually making it. Of course if you actually call the function, it will need to have a function body found at link time. Likewise if you actually use an extern var, it will need to find a var body at link time. Otherwise you get errors.


So yeah, only 1 cpp file has the variable. The others use 'extern' to link to that var. Yeah it's a pain in the ass -- which is one of the reasons why I avoid global vars like the plague.

EDIT:

To avoid a pain in the ass, you can sort of cheat with clever use of #defines



// your header file (referred to as "include.h" below)

#ifdef DO_NOT_MAKE_EXTERNS
#define _EXTERN
#else
#define _EXTERN extern
#endif


_EXTERN int Var1;
_EXTERN int Var2;
//etc




// in **ONE** of your cpp files
#define DO_NOT_MAKE_EXTERNS
#include "include.h"

// rest of file here




// in all the other cpp files

#include "include.h" // note, no #define here

//rest of file here




That'll make it easier to manage a large file full of global vars. The #define _EXTERN saves you from having to make (and maintain) two sets (bodied and body-less) since it keeps both in the same file.


(edited by Disch on 08-06-05 11:25 AM)
(edited by Disch on 08-06-05 11:41 AM)
(edited by Disch on 08-06-05 11:49 AM)
beneficii

Lakitu
Level: 36

Posts: 387/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 08:46 PM Link | Quote
Originally posted by Disch
If you define a variable to be global, it will have global scope (Global meaning it exists for the whole program). If you #include a header file which has a var declaration in several .cpp files, each .cpp file will create its own variable with the same name. This is where your problems are coming from.

The solution here is to make the variable once, then link it so that all .cpp files have access to it.


int myVar; /* will actually make the variable -- only have 1 of these */

extern int myVar; /* will not make the variable, will link to it after compile time -- have one of these for each .cpp file beyond the first */


Of course extern int myVar will only work if 'int myVar' is declared somewhere in your program.

For a halfway decent analogy of why it works this way... making the actual variable (int myVar) actaully makes the variable with a "body". Similar to how making a function with a body gives the function it's body. If you have a function in your program which has several bodies, you'll get errors much like the ones you were getting -- because you were making several different variables which have the same body -- and the compiler doesn't know which one you want to use.

Making it 'extern' says "okay, this variable exists... but not in this .cpp file, so we'll link to it, but it won't be in this compile" -- which is kind of like a body-less variable. Equivilent to having a function prototype (function without a body). It's making the function/var available for use, but without actually making it. Of course if you actually call the function, it will need to have a function body found at link time. Likewise if you actually use an extern var, it will need to find a var body at link time. Otherwise you get errors.


So yeah, only 1 cpp file has the variable. The others use 'extern' to link to that var. Yeah it's a pain in the ass -- which is one of the reasons why I avoid global vars like the plague.

EDIT:

To avoid a pain in the ass, you can sort of cheat with clever use of #defines



// your header file (referred to as "include.h" below)

#ifdef DO_NOT_MAKE_EXTERN
#define _EXTERN
#else
#define _EXTERN extern
#endif


_EXTERN int Var1;
_EXTERN int Var2;
//etc




// in **ONE** of your cpp files
#define DO_NOT_MAKE_EXTERNS
#include "include.h"

// rest of file here




// in all the other cpp files

#include "include.h" // note, no #define here

//rest of file here




That'll make it easier to manage a large file full of global vars. The #define _EXTERN saves you from having to make (and maintain) two sets (bodied and body-less) since it keeps both in the same file.


Okay, so I would have to add _EXTERN in front of every variable in the header file? Also, put in DO_NOT_MAKE_EXTERN and DO_NOT_MAKE_EXTERNS or was that a typo? Thanks.
Dish

Spiny
Level: 38

Posts: 501/596
EXP: 355646
For next: 14801

Since: 03-15-04
From: Disch

Since last post: 18 days
Last activity: 18 days
Posted on 08-06-05 08:48 PM Link | Quote
Originally posted by beneficii

Okay, so I would have to add _EXTERN in front of every variable in the header file?


Yes. That will make it bodied or body-less depending on whether or not DO_NOT_MAKE_EXTERNS was defined before including the header.


Also, put in DO_NOT_MAKE_EXTERN and DO_NOT_MAKE_EXTERNS or was that a typo? Thanks.


sorry, that was a typo. It doesn't matter what it is as long as it's the same thing both times. *me goes to edit post to correct that*


(edited by Disch on 08-06-05 12:00 PM)
beneficii

Lakitu
Level: 36

Posts: 388/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 08:55 PM Link | Quote
Originally posted by Disch
Originally posted by beneficii

Okay, so I would have to add _EXTERN in front of every variable in the header file?


Yes. That will make it bodied or body-less depending on whether or not DO_NOT_MAKE_EXTERNS was defined before including the header.


Also, put in DO_NOT_MAKE_EXTERN and DO_NOT_MAKE_EXTERNS or was that a typo? Thanks.


sorry, that was a typo. It does matter what it is as long as it's the same thing both times. *me goes to edit post to correct that*


I think I understand what this does. If DO_NOT_MAKE_EXTERN is defined, then it defines __EXTERN as nothing, which makes the variable normal. If it's not defined, then it defines __EXTERN as extern, which makes the variable extern. You only want it one source without the extern, while everyone else should have it, so you define DO_NOT_MAKE_EXTERN for it. Thanks.

EDIT: Ugh this is so frustrating! I did as you said, and it did something new. First, it said:

[Warning] 'vars' initialized and declared 'extern' // for each variable in the header file

then it went right back to complaining about multiple declarations as it did before. I declared DO_NOT_MAKE_EXTERN in one file (and it was for that file ("in file included from file") I didn't get the warnings). Do you have any recommendations?


(edited by beneficii on 08-06-05 12:18 PM)
Dish

Spiny
Level: 38

Posts: 502/596
EXP: 355646
For next: 14801

Since: 03-15-04
From: Disch

Since last post: 18 days
Last activity: 18 days
Posted on 08-06-05 09:48 PM Link | Quote
don't init the var when it's declared.

int myvar = 5; <--- don't do that, it won't like it when the var is extern

Instead init all your vars at program startup -- like call an Init() function or something which sets everything to what you want it to be.
beneficii

Lakitu
Level: 36

Posts: 389/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 09:55 PM Link | Quote
Originally posted by Disch
don't init the var when it's declared.

int myvar = 5; <--- don't do that, it won't like it when the var is extern

Instead init all your vars at program startup -- like call an Init() function or something which sets everything to what you want it to be.


Uh, well, that's going to take some time to correct, because those vars are meant to be constant arrays, but I'll see what I can do.
Dish

Spiny
Level: 38

Posts: 503/596
EXP: 355646
For next: 14801

Since: 03-15-04
From: Disch

Since last post: 18 days
Last activity: 18 days
Posted on 08-06-05 09:57 PM Link | Quote
If they're constant then declare them as constant and then you don't have to worry about that extern crap:

const int myArray[5] = {0,1,2,3,4};

that should work fine. If you still get problems (which I doubt), try making it static as well:

static const int myArray[5] = {0,1,2,3,4};
beneficii

Lakitu
Level: 36

Posts: 390/567
EXP: 299656
For next: 8454

Since: 06-27-04
From: Cordova, TN, USA

Since last post: 14 hours
Last activity: 6 hours
Posted on 08-06-05 10:10 PM Link | Quote
Originally posted by Disch
If they're constant then declare them as constant and then you don't have to worry about that extern crap:

const int myArray[5] = {0,1,2,3,4};

that should work fine. If you still get problems (which I doubt), try making it static as well:

static const int myArray[5] = {0,1,2,3,4};


Okay, thank you! I should have seen that! If a variable is initialized in the declaraqtion it won't let it be extern.

Thank you! It now compiles succesfully.

Onto the next stage of my program and arguably the most challenging: the logic tests!
Add to favorites | "RSS" Feed | Next newer thread | Next older thread
Acmlm's Board - I2 Archive - Programming - C++: Bizarre Multiple Declarations | |


ABII


AcmlmBoard vl.ol (11-01-05)
© 2000-2005 Acmlm, Emuz, et al



Page rendered in 0.009 seconds.