![]() |
|
This thread is locked; no one can reply to it.
![]() ![]() |
1
2
|
extern? |
CGamesPlay
Member #2,559
July 2002
![]() |
Hmm, do you understand what's going on? I notice some confusion on bamccaig's part, so I will give this explanation anyways. Let's have 3 files: badguy.cpp, extras.cpp, and main.cpp. Remember all these files are is text files with a special extension. The compiler doesn't care about this extension at all*. Let's say extras.cpp has a variable that you want to use: // extras.cpp BITMAP* myBitmap = NULL; This is called defining a variable. If we want to use this variable in main.cpp, you use "extern": // main.cpp extern BITMAP* myBitmap; This is called declaring a variable. The difference is that in defining a variable, the compiler allocates space for it in the program's code, whereas in declaring it, the compiler simply learns that there is a variable by that name defined elsewhere. As you already know, "extern" tells the compiler "a variable with the name myBitmap exists, but I am not defining it here. You will get more information about this variable later on". When you compile this, the compiler compiles main.cpp into main.o and makes a note: "I need to find the variable myBitmap". When it links main.o and extras.o together (the process that takes the compiled .o files and links them into an executable file), the linker notices that main.o needs to know about myBitmap, which it finds in extras.o. The program is linked, and the compilation is successful. Now, when badguy.cpp also needs to use myBitmap, we do the same thing: // badguy.cpp extern BITMAP* myBitmap; The same process as above happens for badguy.o, and the compilation is successful. What if you forget to declare a variable "extern" once? Like, instead of the badguy.cpp posted above, use this one instead. // badguy.cpp revision 2 (does not link) BITMAP* myBitmap; When the compiler compiles this file, it knows that it has a variable called myBitmap and it allocates space for it in the program's code. When the linker comes to link all of the .o files together, it sees that there is a myBitmap in badguy.o, and a myBitmap in extras.o, and it gives a "multiple definition" error. So, failing to use extern causes multiple definition errors. What if all of the source files declare the variable extern? That is, using this version of extras.cpp (and the first version of badguy.cpp): // extras.cpp revision 2 (does not link) extern BITMAP* myBitmap; When the linker goes to link all of the source files together, it sees that in all 3 files the variable myBitmap is declared someplace else. If it doesn't find any actual myBitmap variable (which is what happens in this example), the linker errors with an "undefined reference" error. So, using extern everywhere and failing to ever define the variable causes undefined reference errors. One more thing. Only the definition of a variable can give it a value: // badguy.cpp revision 3 (does not compile) extern BITMAP* myBitmap = NULL; The compiler will see that line, emit a warning that an extern variable was initialized, but the compiler will treat the variable as though it weren't extern at all. This can cause "multiple definition" errors, as above. That's how not to use extern. How do header files come into this? Obviously, if you had 10 or 15 variables in badguy.cpp, you wouldn't want to list them all in every source file that used them. To help this problem, we have "header files". Remember, all of the files we are dealing with are just text files. The extension on the file name is simply so we as programmers know the nature of the content in side the file. Let's create an extras.h file for our extras.cpp: // extras.h extern BITMAP* myBitmap; Then, let's modify our 3 other files to use this include file: // extras.cpp revision 3 #include "extras.h" // Beginning of extras.cpp code (#include finished) BITMAP* myBitmap; // main.cpp revision 2 #include "extras.h" // badguy.cpp revision 3 #include "extras.h" When the compiler goes to compile these files, it preprocesses them before it compiles them. If you create the four files shown above and run "gcc -E extras.cpp", you will see the output of the preprocessor. This is what you would see: (technically, the comments would be removed from the result file, I'm keeping them for clarity. You see? The compiler just flat-out copied the contents of the include file straight into the line where #include happened. In all the other source files, they end up looking exactly like they did before. This one looks a little different, though. What happens when the compiler compiles it? The compiler reads the "extern BITMAP* myBitmap" line, so it knows there is a variable myBitmap that code can use, but it will be defined (space will be made for it) later. Then it gets to the "BITMAP* myBitmap" line, and actually makes space for that variable. The compilation is successful. Sometimes you will see function declarations in header files, also: // extras.h revision 2 extern BITMAP* myBitmap; void loadMyBitmap(); That last line tells the compiler about (it "declares") a function called loadMyBitmap, that will be defined somewhere else in the code. Then, extras.cpp comes along and actually defines the function: // extras.cpp revision 4 #include "extras.h" BITMAP* myBitmap; void loadMyBitmap() { myBitmap = load_bitmap("image.bmp", NULL); } The same process happens as for variables, and the compilation is successful. Take note: these two lines of code are entirely equivalent: void loadMyBitmap(); extern void loadMyBitmap(); Phrased differently, functions are declared extern by default. I think I've covered everything I wanted to about extern, and this should give you a more technical explanation of what extern and #include are doing. * Technically, it does care about them, but not for anything discussed in this post -- Ryan Patterson - <http://cgamesplay.com/> |
ImLeftFooted
Member #3,935
October 2003
![]() |
Quote: Is it right to call them multiple extern variables? It's one variable made available to many files. I think. There is nothing stopping John.cpp and HotGuy.cpp from ignoring Kate.h entirely and making their very own extern void *boyfriend variable reference. There are rules as to how these multiple externs can co-exist, but a given application can have a theoretical infinite number of them. |
bamccaig
Member #7,536
July 2006
![]() |
// file1.cpp int x = 0;
// file2.cpp extern int x; I thought that when referencing x in both file1.cpp and file2.cpp that you were actually using the same variable; not value, variable. Are you saying that file2.cpp's x is actually a reference to file1.cpp's x; equivalent to pass by reference? For example: // file1.cpp int x = 0; void main(void) { displayX(x); }
// file2.cpp #include <iostream.h> int displayX(int &x) { cout << x; }
-- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
CGamesPlay
Member #2,559
July 2002
![]() |
Quote: I thought that when referencing x in both file1.cpp and file2.cpp that you were actually using the same variable Yes, this is correct. I'm referring to this: Quote: extern is basically a way to broaden the scope of a variable even further than the entire file. You can then share it between files. I was having trouble remembering how to do this a couple months ago. Hopefully I get it right: // myprogram.h int xintExternalScope = 0; // This is simply declared normally. Current // it has global scope to myprogram.h.
// myprogram.cpp // xintExternalScope is defined in this file... #include "myprogram.h" extern xintExternalScope; // This is saying that it is defined elsewhere // (myprogram.h), but we're using it here as well. int main(void) { return xintExternalScope; }
-- Ryan Patterson - <http://cgamesplay.com/> |
ImLeftFooted
Member #3,935
October 2003
![]() |
Quote: Are you saying that file2.cpp's x is actually a reference to file1.cpp's x; equivalent to pass by reference? Nah, I'm just trying to say is that this is possible: // file1.cpp int x = 0;
// file2.cpp extern int x;
// file3.cpp extern int x;
|
X-G
Member #856
December 2000
![]() |
That's just the same declaration again. In fact, that's how it normally works. -- |
Albin Engström
Member #8,110
December 2006
![]() |
HOLY SHIT!! these great blocks of information just comes dropping down on me.. thanks a thousand times |
Samuel Henderson
Member #3,757
August 2003
![]() |
Quote: where do you guys get all the information? experience? Yes. (Says the guy who did not add a single idea to the thread) ================================================= |
Tobias Dammers
Member #2,604
August 2002
![]() |
Quote: where do you guys get all the information? experience?
- experience --- |
CGamesPlay
Member #2,559
July 2002
![]() |
I assimilate the memories of all creatures whom I consume, and I like the taste of skilled programmers (very tender). -- Ryan Patterson - <http://cgamesplay.com/> |
Tobias Dammers
Member #2,604
August 2002
![]() |
Yeah, the fingers are the best part, apart from the brains of course. Yum! --- |
Albin Engström
Member #8,110
December 2006
![]() |
Tobias Dammers said:
- experience the only thing i have in common with that list is allegro.cc.. - - CGamesPlay said: I assimilate the memories of all creatures whom I consume, and I like the taste of skilled programmers (very tender). nice, i'd love to have that ability.. - - |
|
1
2
|