Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » extern?

This thread is locked; no one can reply to it. rss feed Print
 1   2 
extern?
CGamesPlay
Member #2,559
July 2002
avatar

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.


That's the correct usage of extern. Here is the incorrect usage:

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.

// extras.cpp revision 3
// extras.h

extern BITMAP* myBitmap;
// Beginning of extras.cpp code (#include finished)

BITMAP* myBitmap;

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.


How does "extern" apply to functions?

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

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Dustin Dettmer
Member #3,935
October 2003
avatar

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
avatar

// 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;
}

CGamesPlay
Member #2,559
July 2002
avatar

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;
}

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Dustin Dettmer
Member #3,935
October 2003
avatar

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
avatar

That's just the same declaration again. In fact, that's how it normally works.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Albin Engström
Member #8,110
December 2006
avatar

HOLY SHIT!! these great blocks of information just comes dropping down on me.. :o.
Thanks a lot!! wasn't sure about "defining and declaring" and didn't know shit about .o! if only there where tutorials(maybe not the right word) THIS good.. :/ out there.. where do you guys get all the information? experience?

thanks a thousand times :).

Samuel Henderson
Member #3,757
August 2003
avatar

Quote:

where do you guys get all the information? experience?

Yes.

(Says the guy who did not add a single idea to the thread)

=================================================
Paul whoknows: Why is this thread still open?
Onewing: Because it is a pthread: a thread for me to pee on.

Tobias Dammers
Member #2,604
August 2002
avatar

Quote:

where do you guys get all the information? experience?

- experience
- good programming books
- reading other people's code
- allegro.cc
- black magic

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

CGamesPlay
Member #2,559
July 2002
avatar

I assimilate the memories of all creatures whom I consume, and I like the taste of skilled programmers (very tender).

--
Tomasu: Every time you read this: hugging!

Ryan Patterson - <http://cgamesplay.com/>

Tobias Dammers
Member #2,604
August 2002
avatar

Yeah, the fingers are the best part, apart from the brains of course. Yum!
Have you ever tried LISP programmers? Their brains have an excellent texture, goes well with a good Chardonnay.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Albin Engström
Member #8,110
December 2006
avatar

Tobias Dammers said:

- experience
- good programming books
- reading other people's code
- allegro.cc
- black magic

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 


Go to: