Creating a variable that is accessible from multiple source files

Discussion in 'Mac Programming' started by Cromulent, Mar 23, 2008.

  1. macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #1
    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.
     
  2. macrumors 68040

    Joined:
    Apr 22, 2005
  3. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #3
    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
     
  4. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #4
    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

    Code:
      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

    Code:
      int x; 
    
    or

    Code:
      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.
     
  5. thread starter macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #5
    Read it before and still gives me the same problem.

    Example using made up names.

    Code:
    global.h
    
    extern int sock;
    
    main.c
    
    #include "global.h"
    
    ...
    int sock = 0;
    ...
    
    connection.c
    
    #include "global.h"
    
    ...
    
    etc etc

    results in:

     
  6. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #6
    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.
     
  7. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #7
    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
     
  8. thread starter macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #8
    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.

    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.
     
  9. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #9
    Here's what I came up with, which seems to work A-OK:

    global.h:
    Code:
    extern int x;
    main.c:
    Code:
    #include <stdio.h>
    
    int x;
    
    int main(int argc, char *argv[]) {
      x = 10;
      external_function();
      return 0;
    }
    ext.c:
    Code:
    #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?
     
  10. macrumors G5

    gnasher729

    Joined:
    Nov 25, 2005
    #10
    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.
     
  11. thread starter macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #11
    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

    Code:
    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.
     
  12. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #12
    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:
    Code:
    int x;
    
    int get_socket() {
      return x;
    }
    
    void set_socket(int set_val) {
      x=set_val;
    }
    main.c:
    Code:
    int main(int argc, char *argv[]) {
      set_socket(11);
      external_function();
    }

    ext.c:
    Code:
    #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.
     
  13. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #13
    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!!!
     
  14. thread starter macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #14
    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?
     
  15. macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #15
    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
     
  16. thread starter macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #16
    Ah, I see. Thanks for the help. That looks like a much cleaner way of doing it.
     

Share This Page