![]() |
|
#1
|
|||
|
|||
Global VariablesMy program's classes and functions all use the same vector<Data> or map<string,vector<Data> > etc, variables. As a result, rather than pass the same 5 things to every function, is there someway to make them global variables?
Keep in mind the classes #include each other, but I've kept it down to a minimum. The problem is any variables declared in the classes, even with include guards, still will create linking errors. I know for a fact the program worked while passing, but to make things cleaner I changed it yesterday. The error consists of around 45 "blahblah is already defined in Initialization.cpp". Someone recommended using extern, but I didn't really understand how to use that to fix the linking errors. C++, Visual Studio |
|
#2
|
|||
|
|||
Re: Global VariablesQuote:
Quote:
An include guard prevents a file from being included more than once in the same compilation unit. So if <a.h> includes <b.h> and <b.h> and <c.h> includes <b.h> then the guard will work just as you intend it in case a file includes both <a.h> and <c.h> Note that if you project is spread among several source files (.cpp files), they are compiled separately. It's a language feature, not implementation-dependent. So: if x.cpp includes <a.h> and y.cpp includes <a.h>, then the file is included when x.cpp is compiled. The file is also included when y.cpp is compiled. The include guards simply do not (and can not) prevent this. If storage is allocated in <a.h>. then there will be a conflict when the files are linked. Period. Full stop. That is one reason to never put anything that creates storage in a header file. It's not illegal to have variable declarations in a header file, it's just not very useful. There have been several threads about using extern statements in headers for global variables. If you need another example, specifically with classes: CPP / C++ / C Code:
CPP / C++ / C Code:
CPP / C++ / C Code:
CPP / C++ / C Code:
CPP / C++ / C Code:
I used GNU g++ to compile them all together g++ -Wall -W -pedantic main.cpp func.cpp -o main But if they are all part of your Visual C++ project, the results will be the same. Using command line visual C++ compiler: cl main.cpp func.cpp /EHsc Output: Code:
Note: Nothing in any header file actually allocated storage! File scope variables and non-static functions in one file can be accessed in other files by declaring them extern in the other file (or in a header included by the other file). Regards, Dave Disclaimer: Globals are legal in C and C++. Sometimes it is appropriate and useful to have globals. Use of globals as a general programming practice is not considered desirable, for a number of what I consider to be very good reasons (which you are, of course, free to ignore). |
|
#3
|
|||
|
|||
Re: Global VariablesThanks, that seems to make sense, though I can't test it right now I will post back later. However, does it make any difference that the classes themselves must reference the global variables that are made using their classes?
IE: Whenever a new Data is made, it randomly copies from vector<Data> defined in Globals.h . Upon use, it would have been initialized in main, I just wonder if linking errors would occur because they both need each other. |
|
#4
|
|||
|
|||
Re: Global VariablesQuote:
Quote:
If you have a vector object declared in globals.h, you will have problems linking (but you already said that you have problems linking). If you have a variable (vector object or whatever...) in a source file and it is declared extern in some file that instantiates a Data object then the declaration of the object can pass a value from the "global" vector to the constructor as a parameter, if that is what you are trying to do. Whenever a new Data is made, its constructor is called. Whatever the constructor does, it does. If the object instantiation uses a global variable as a parameter to the constructor, it is used however the constructor uses its parameter. Give an example of what you really want to do. Compile it first to see if it's allowed. If you don't understand what the compiler tells you, then post the code and post the messages. Try to reduce the amount of code to a small number of files with the smallest amount of code that still exhibits the problem. In other words, don't tell us what you are trying to do; show us. Regards, Dave Last edited by davekw7x : 20-Feb-2007 at 10:54.
|
|
#5
|
|||
|
|||
Re: Global VariablesI'm not sure what the meaning of declaring the variables for "scope". Aren't they supposed to be external and therefore accessible from everywhere? Well it's clear they're not, but does declaring them in main let them be used in all other files as well?
I have given an attempt at extern-ing the variables, and placing them also about main(). This has given moderate success, but leaves a problem. A majority of the error messages (26) talk about my RANDOM.H being redifined. It contains the randomizer class/functions. I have not messed with the definition of this at all after making sure it worked, except to put it in the Globals.H. Thus everything in the file is being redefined in every file. I might be able to figure it out tommarrow, but if you have a chance I'd be grateful if you showed how to fix that. CPP / C++ / C Code:
If you wish, I could show you what it does, but because it's all custom classes/functions I would have to post like 5 pairs of H/CPP files for it to make sense. Therefore I felt the easiest way was just to show the code that mattered (the #includes). However, because you asked specifically, here's the thing that brings everything together: CPP / C++ / C Code:
The result is a random Equipment (Equipment Data + 2 Magic Modifiers). First it selected a random Equipment_Data, then searches a map for that Equipment Type (Armor/Sword/Etc), and picks a random magic modifier from the list (Fire/Godly/of Doom/Etc). NOTE: picking based on that map is one of the recent changes I made which made me decide to make globals (adjusting all the functions just to pass a variable every time I add a new features is quite time consuming). If you would like to see any of the code for loading in the vectors and maps, I'd be happy to post, as I'm sure there is probably a more efficient method. |
|
#6
|
|||
|
|||
Re: Global VariablesQuote:
In the file where the items are defined, unless you declare them static, variables and functions with file scope (that is, they are defined outside of all functions in that file) are also available for use in other files at link time. In order to actually use them in other files, the will be have to be declared extern in the other files (or in headers included by the other files) so that the compiler will work without any local definitions. Then the linker looks in other object files for the variables (or functions) so that everything can go together. Quote:
Quote:
Is RANDOM.H the file name of the header? Exactly what are the messages? Instead of telling us what they "talk about", how about showing us the exact messages? Are they compile-time errors? If so and the stuff being "redefined" is in RANDOM.H, then they should be eliminated with inclusion guards in RANDOM.H (or is it RANDOM.h ?) Regards, Dave Footnotes: If you can stand one more example: Here are two files. Just to keep it simple, no headers are involved. First I call them main.c and x.c and compile as C files. Then I will call them main.cpp and x.cpp and compile as C++. If you are doing simple stuff now (with everything in one or two files), you may be able to tweak around and get things to work so that you can execute your program and complete your assignment. But if you come to a real understanding of the use of external linkages with this simple example, it will do you a world of good when you get to real projects with more and larger files to work with. After you complete the tests that I suggest below, go back and put the extern declarations in header file(s). Try to include the header(s) in either or both files. Compile together. Compile separately. Use inclusion guards. Omit inclusion guards. The two files together contain a total of about 15 lines of code.Grab them by the throat and wrestle them to the ground. Let them know that: Resistance is Futile! Knowledge Will Be Assimilated! CPP / C++ / C Code:
CPP / C++ / C Code:
Now, compile them together gcc -Wall -W -pedantic main.c x.c -o main or cl main.c x.c Then a run looks like this: Code:
Try compiling them separately: cl -c main.c cl -c x.c cl main.obj x.obj or gcc -c -Wall -W -pedantic main.c gcc -c -Wall -W -pedantic x.c gcc main.o x.o -o main (Borland users use bcc or bcc32 or whatever instead of cl.) Now try without the extern void func(int) statement in main.c. That is, comment it out. Depending on the compiler and the warning message level setting you may get a compile-time warning about "Implicit declaration of func()", but everything will actually work in C for this particular function, because of the legacy behavior that lets the compiler generate code for functions as though they have int return types and all of their arguments are ints. (Note that the function invocation code prepared by the compiler for a void function is apparently the same as that for an int function,) In C++ this is an error since you must declare functions before using them. Rename or make copies of the files to be main.cpp and x.cpp and compile again (with cl or bcc the command is the same, with GNU compilers use g++ instead of gcc on the command line). Function calling is much more complicated (from the compiler's point of view) in C++ than in C, primarily because of the possibility of having functions with the same name but different parameter types. Now if put the extern func() statement back into main.c but comment out the extern int x;. Whether this is C or C++, this is a compile-time error since there is no default behavior for variables. The storage class of a variable must be known when the variable is first encountered in any file that is being compiled. Note that no "extern" declarations are needed (for the variable or the function) in x.c, since functions and file scope variables, by default, are available for linking to other object files. Now, go back and uncomment the extern x statement in z.c and declare x to be static in x.c. CPP / C++ / C Code:
Try the same with func: declare it static in x.c. (Remove the static on x)The two files compile ok separately, but there will be a link error when you try to put them together. I respectfully suggest (if anyone out there is still awake) that, if you are interested, you should actually go through these steps. Don't just read them and nod your head and say, "that makes sense." Test them for yourself. Make sure each and every bit of behavior is exactly the way it "should" be. I try very hard to post things exactly as I have used them, but sometimes I screw up. Make sure that my description fits the behavior on your system and with your compiler. If not (or if it works but doesn't make sense), then please ask. But be specific about what you did and what you saw (compiler messages, linker messages or whatever) when you compiled and/or linked and/or executed the programs. Last edited by davekw7x : 21-Feb-2007 at 00:35.
|
|
#7
|
|||
|
|||
Re: Global VariablesI hope I'm not intruding, and you've probably solved your problem using the help given by davekw7x....
Have you heard of the Singleton Pattern? Simple to implement in C++. Just create a header/source combo that contains extern defined objects ( or variables ) and suddenly you have objects that have only a single instance throughout your code. IOW, Code:
and Code:
This means that storage is only allocated once, in the "source" object file, and any other files that include "header.h" can reference that one instance. This alleviates all your problems with global variables. IME, I find it better to have an actual class that controls all the data management, and then make everyone else talk to that one object. It makes the memory management that much simpler, and frees you up if you decide to make design changes. I find the singleton pattern and user-space threads (an example being GNU's Pth) to be a very efficient and easily comprehended design. |
|
#8
|
|||
|
|||
Re: Global VariablesRANDOM.h is actually the file name. What I mean specifically is this:
Code:
As you can see, this is the only remaining error really (I said mostly, but I fixed the other one. I realized I was initializing the variable in the extern, which is a no-no.). The .h file does have include guards, but as you see that doesn't stop it from being defined separately in each file. It has occured to me: The RANDOM.h file has all the function definitions in it, should those be in a separate .cpp file? It was never a problem before, but I didn't write the randomizer. |
|
#9
|
|||
|
|||
Re: Global VariablesQuote:
Yes! Yes!! Yes!!! These are linker errors. That's why we recommend that header files don't contain executable code or anything that allocates storage. Inclusion guards perform a valuable task at compile time but have absolutely no effect at link time, since the stuff in the included file has been absorbed by the preprocessor before compilation even took place. (That is: Since preprocessor directives no longer exist by the time the object files are created, they can have no effect at link time.) Here is what that first message is trying to tell us (although the compiler message doesn't know the actual name of the header file): Apparently you have a file named Initialization.cpp, which includes RANDOM.h, and you have a file named Equipment_Date-gen.cpp, which also includes RANDOM.h RANDOM.h apparently has definitions for the various functions Random::uniform, etc. When you compiled the file Initialization.cpp, the object file that was created contains code and symbol table entry for Random::uniform, etc. The compiler was happy: everything is defined. When you compiled the file Equipment_Data-gen.cpp, the object file that was created contains code and symbol table entry for Random::uniform, etc. The compiler was happy: everything is defined. When the linker tries to put the object files together it can't combine the symbol tables since there are some of the functions in one part of the symbol table (the part from Initialiation.obj) that would have the same name and parameters as some of the functions in another part of the symbol table (the part from Equipment_Data-gen.obj). The linker will not (can not; should not) go back and figure out that the functions are actually the same so it would be ok to simply use one and ignore the other. One more time: If you are going to include anything from different compilation units (i.e. from different source files) than don't put anything in the included file that generates code or allocates storage. Regards, Dave |
|
#10
|
|||
|
|||
Re: Global VariablesThanks a lot. I put the function data into a cpp file, and that fixed everything. This exercise has helped me understand the linking phase much better, and I feel confident that if a similar problem arises in the future I could locate and fix it.
Thanks for your help. |
Recent GIDBlog
Developing GUIs with wxPython (Part 4) by crystalattice
| Thread Tools | Search this Thread |
| Rate This Thread | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Global variables | Kezern | C++ Forum | 1 | 01-Aug-2006 08:27 |
| How do you SAFELY pass hidden variables through merchant account payment screens? | mrsurrey | eCommerce / Merchant Account Forum | 4 | 03-Jul-2006 15:28 |
| linking libraries removes variables | svhb | C++ Forum | 1 | 06-Dec-2005 03:50 |
| The Use of GLobal variables | Peter11111 | C Programming Language | 3 | 12-Aug-2005 08:08 |
| variables return to previous value after i try to set them | nasaiya | MS Visual C++ / MFC Forum | 2 | 14-Jun-2005 00:43 |
Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The