PDA

View Full Version : Creating a variable that is accessible from multiple source files




Cromulent
Mar 23, 2008, 06:22 PM
I'm having real problems getting this to work. I've read all about extern variables etc and how they work etc. The problem is that when using an extern int for instance does the value of that int get changed on a global level or when you initialise it within a specific function?

I need the value to be a global value that is changeable and useable across the whole project and multiple files. I realise that I could just pass it as a function argument but it is just one int that I would like to keep global as it is used throughout the program and passing it as an argument just adds unnecessary complexity.

I've looked at system header files but I don't think they need the variable to keep its global value.

I need to have an int variable which I can put in a header file and include in multiple files in the same project (which by the way I am also having problems with even if I do use the method shown here : http://www.bobarcher.org/software/include/index.html). How would one go about doing this?

Edit : I've read things like http://www.doc.ic.ac.uk/lab/secondyear/cshort/docs/node17.html and still find when linking that I get multiple symbol errors. Surely the extern keyword lets the compiler / linker know that the symbol is going to appear in more than one object file?

Edit 2 : After playing around with my code I guess it will work fine if I just pass it as a function argument. Hopefully it won't add too much complexity.



admanimal
Mar 23, 2008, 07:05 PM
http://www.thescripts.com/forum/thread200667.html

lazydog
Mar 23, 2008, 07:12 PM
Hi

Think of global functions. A function defined in one .c file is accessible from another .c file by including a prototype for the function. It's the same with global variables. A global variable defined in one .c file is accessible from another .c file by including an extern definition for the variable. In both cases, there is only ever one instance of the function or variable defined in the final program. Unless you use the static keyword, any variable defined at the global scope of a .c file is global to the whole project, again, just like functions.

b e n

gnasher729
Mar 23, 2008, 07:20 PM
What you are looking for is a "global variable".

Let's say you want a global variable of type int with a name x. Best thing to do is to put an extern declaration into a header file, like

extern int x;

and include the header file whereever the variable is needed. Then in _one_ single source file, you add the definition of the variable, like

int x;

or

int x = 999;


That's all there is to it, that is from the technical point of view. In practice, there are a few things to observe: First, you should give a global variable a meaningful name that is very unlikely to be used by anyone else who wants a global variable for a different purpose (if two different sets of source files use global variables with the same name for different purposes then you are in trouble). Second, it is a good idea to have a naming convention that tells you something is a global variable just by looking at the name. Third, only use global variables when needed; never use them when a static variable would do. Fourth, it is often better to have accessor functions that might modify a static variable, instead of using a global variable. Fifth, global variables often give you a headache when you use multiple threads, because a global variable is the same for all running threads.

Cromulent
Mar 23, 2008, 07:23 PM
http://www.thescripts.com/forum/thread200667.html

Read it before and still gives me the same problem.

Example using made up names.

global.h

extern int sock;

main.c

#include "global.h"

...
int sock = 0;
...

connection.c

#include "global.h"

...

etc etc

results in:

"_sock", referenced from:
_sock$non_lazy_ptr in nntpSetup.o
_sock$non_lazy_ptr in nntpMessageRetrieval.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
Build failed (1 error)

gnasher729
Mar 23, 2008, 07:35 PM
I've read things like http://www.doc.ic.ac.uk/lab/secondyear/cshort/docs/node17.html and still find when linking that I get multiple symbol errors. Surely the extern keyword lets the compiler / linker know that the symbol is going to appear in more than one object file?

I just had a look at the site you were linking to. It is horrifying! I realise that it tries to show how to use "extern", but its use of extern variables strongly violates many principles of decent programming:

1. Global (extern) variables are used when static variables would have been fine.

2. The choice of variable names for the extern variables is horrific. They were called "max", "line" and "longest". If you choose names like that, chances are that in some other code you will choose the same names for extern variables, and then you are in trouble, like calling a completely unrelated function might change the variable "max" unexpectedly.

3. Using names that don't follow any naming convention makes the code hard to read and error prone. For example, if instead of "extern int max" you write "int max" inside some function, the code will compile fine - but it won't access "max" as intended. Or lets say I write some code that is added to your application. I use a local variable "max". Instead of writing "int min, max;" I write "int min, ma;". This will compile, if max is somewhere in a header file, and modify the global max unintentionally.

lazydog
Mar 23, 2008, 07:38 PM
Hi

Gnasher has made some excellent comments on globals.

Back to your problem, have you tried deleting the object files and compiling from fresh?

b e n

Cromulent
Mar 23, 2008, 07:41 PM
I still don't understand why this is working for me. Despite doing what has been said in this thread and what was linked before in the second post, this just is not working.

Hi

Gnasher has made some excellent comments on globals.

Back to your problem, have you tried deleting the object files and compiling from fresh?

b e n

Yep, numerous times. I normally avoid globals completely, but in this one instance it really is a very useful thing to have as a global. I've renamed it to something that is extremely unlikely to be duplicated elsewhere too.

lee1210
Mar 23, 2008, 07:44 PM
Here's what I came up with, which seems to work A-OK:

global.h:
extern int x;

main.c:
#include <stdio.h>

int x;

int main(int argc, char *argv[]) {
x = 10;
external_function();
return 0;
}

ext.c:
#include "global.h"
#include <stdio.h>

void external_function() {
printf("The value is: %d\n",x);
}

Built using:
cc -c ext.c
cc ext.o -o testex main.c

Don't include global.h in your main source file, where you actually globally declare the variable. That will lead to "already defined" errors, because there's already a variable of that name in the global scope.

-Lee

Edit: I actually just tried it, and including global.h in my main file worked fine. Who'd've thunk?

gnasher729
Mar 23, 2008, 07:46 PM
Read it before and still gives me the same problem.

Strange, you get exactly the error that you should get if there is no definition of the variable. Check that main.c is actually a part of your project, and check that "sock" is correctly spelt, and that the definition in main is in a part that actually is compiled, and that is not inside any function.

Cromulent
Mar 23, 2008, 07:47 PM
Ahhh that was the problem.

I thought when you initilised the variable in the normal code for the first and only time you had to do it within a function. Taking it outside of a function made it work perfectly.

So I now have

global.h

extern int gnntpSock;

main.c

int gnntpSock = 0;

main()
...

Thanks for your help. I thought I was going crazy for a bit there.

lee1210
Mar 23, 2008, 07:52 PM
I'm going to make one more suggestion on this one. You might want to only include global.h in one source file, and in there declare an accessor and mutator for it (OOP terms don't really apply, but hopefully that's clear). That way in other areas of the code when you need to use that variable, there's an extra step to call these functions, but it makes the variable a little "less global", since there's only one file that accesses it directly.

Example:
global_accessor.c:

int x;

int get_socket() {
return x;
}

void set_socket(int set_val) {
x=set_val;
}

main.c:

int main(int argc, char *argv[]) {
set_socket(11);
external_function();
}


ext.c:
#include <stdio.h>

void external_function() {
printf("The value is: %d\n",get_socket());
}

built with:
cc -c global_accessor.c
cc -c ext.c
cc ext.o global_accessor.o -o testex main.c

Edited to take into account lazydog's suggestion also, it's a good one.

lazydog
Mar 23, 2008, 07:52 PM
Hi Cromulent,

Have you got any conditional compilation directives around the bit of code that defines sock? You could try moving the declaration of sock (ie int sock = 0 ;) out from main.c and into one of the other files (doesn't matter which).

One other thought springs to mind, are you building a library which does not have main.o linked to?

b e n

EDIT: Glad you solved it!!!

Cromulent
Mar 23, 2008, 07:59 PM
I'm going to make one more suggestion on this one. You might want to only include global.h in one source file, and in there declare an accessor and mutator for it (OOP terms don't really apply, but hopefully that's clear). That way in other areas of the code when you need to use that variable, there's an extra step to call these functions, but it makes the variable a little "less global", since there's only one file that accesses it directly.

I haven't come across those terms in my C travels yet. I thought they were more to do with C++?

You mean basically put the variable in a function and then call the function everytime you want access to the variable? Or am I misunderstanding you?

lee1210
Mar 23, 2008, 08:01 PM
I haven't come across those terms in my C travels yet. I thought they were more to do with C++?

You mean basically put the variable in a function and then call the function everytime you want access to the variable? Or am I misunderstanding you?

I stuck an example in afterwards to try to clarify. Like I said, accessor and mutator normally apply to a private element of a class in an Object-Oriented language (like C++). Instead of things being able to immediately access the variable, they have to go through the "accessor"(get the value) or "mutator"(modify the value). I didn't know what to call these functions for a global variable, so I just used those terms.

Essentially the idea is that you have something between you and the global variable, so if you want to change its name, put it in a database, etc. you can do so and only have to change one source file.

-Lee

Cromulent
Mar 23, 2008, 08:22 PM
I stuck an example in afterwards to try to clarify. Like I said, accessor and mutator normally apply to a private element of a class in an Object-Oriented language (like C++). Instead of things being able to immediately access the variable, they have to go through the "accessor"(get the value) or "mutator"(modify the value). I didn't know what to call these functions for a global variable, so I just used those terms.

Essentially the idea is that you have something between you and the global variable, so if you want to change its name, put it in a database, etc. you can do so and only have to change one source file.

-Lee

Ah, I see. Thanks for the help. That looks like a much cleaner way of doing it.