Thread: Control over variables inside a header file

  1. #1
    Astrophysics student Ayreon's Avatar
    Join Date
    Mar 2009
    Location
    Netherlands
    Posts
    79

    Control over variables inside a header file

    My code is spread out over several .c files and their respective header files. I have one header file (without a .c file), which contains the definitions of some variables I wish to use in all other .c files.
    In the main I wish to give these variables values.

    How can I do this, so that all the other .c files will use the updated versions of the variables?

    So in this header file I have something like:
    double x ;

    In the main I want to do something like x = 2, and make sure all the other .c files that included the header, use x=2.
    Nothing to see here, move along...

  2. #2
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You should look at the word "extern".

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    That's a global variable, and if it is declared in a header #included in all your .c files, then you will get what you want.

    You can use extern here but it is then slightly more complicated and I'm guessing probably not necessary in this case if the header is just simple global variables like you say.
    Last edited by MK27; 06-23-2011 at 08:57 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    I don't generally declare variables in header files... I generally do it like this...

    Code:
    // .c file where variable originates
    long x = 0;  
    
    
    // .h file making it visible elsewhere
    extern long x;
    As already explained the extern keyword makes a promise to the compiler that the variable exists someplace where it is reachable. You should note that variables declared in this manner are global in scope, complete with all the problems that can bring. The use of global variables should be minimized whenever possible.

  5. #5
    Astrophysics student Ayreon's Avatar
    Join Date
    Mar 2009
    Location
    Netherlands
    Posts
    79
    In my many attempts to fix my code I might have tried this already, but I was also using static and extern all over the place.
    Now all I have in my header file is (just an example):
    double x;

    in my .c file:
    x = 2 ;
    printf("x = %f", x) ; //prints 2 like I want it to
    //run some functions from other .c files that use x...
    printf("x = %f", x) ; //still prints 2


    Then once I call a certain function, x is changed again (to some weird number it seems).
    To my knowledge I only use this x, and don't change it anywhere.
    What could cause x to suddenly change again?

    EDIT: Actually it doesn't appear to work at all. Those functions that I ran, which did not appear to change x, use x in their argument.
    After running a function that uses x inside itself (so not through an argument), it becomes apparent that x still or again has a rubbish value.
    Last edited by Ayreon; 06-23-2011 at 09:26 AM.
    Nothing to see here, move along...

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    That's because, declaring the variable in the header creates separate copies of it in each .obj file when it's compiled. Then when the program is linked you end up with "x in a.c" "x in b.c" etc.

    If you declare it once in the most relevent .c file and use extern in the header, the compiler will connect them all together.

    That said... it is probably a better idea to simply pass x as a parameter to your functions and/or assign it's value from the function's returns. Globalized variables are highly prone to just the kind of magic values you are describing.

    Code:
    // in the header file is (just an example):
    extern double x;
    
    // in the .c file:
    double x;
    // other stuff
    x = 2 ;
    printf("x = %f", x) ; //prints 2 like I want it to
    //run some functions from other .c files that use x...
    printf("x = %f", x) ; // prints result of functions
    Or a better plan....
    Code:
    // in the .h file
    double StuffInOtherFiles(double val);
    
    
    // in the .c file:
    double x;
    // other stuff
    x = 2 ;
    printf("x = %f", x) ; //prints 2 like I want it to
    
    x = StuffInOtherFiles(x);
    
    printf("x = %f", x) ; //prints return value of function
    It strikes me that we might be able to help you better if you posted some snippets of your actual code...

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by CommonTater View Post
    That's because, declaring the variable in the header creates separate copies of it in each .obj file when it's compiled. Then when the program is linked you end up with "x in a.c" "x in b.c" etc.
    True, but this assumes that each .c file is being compiled as a separate object then linked together. You can also compile several .c files all together into a single object all at once, in which case the issue you describe is not a problem. It's not a good way to go for a large project, and using extern and compiling each .c file separately is probably a "better practice" of course.

    Anyway, the deal with extern is that it refers to a variable that is declared somewhere else, globally but out of file scope, once, without extern. That could be in a header or in a .c. What Common Tater describes should work. If not, post all the actual declarations with the actual filenames and relevant #include declarations.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by MK27 View Post
    True, but this assumes that each .c file is being compiled as a separate object then linked together. You can also compile several .c files all together into a single object all at once, in which case the issue you describe is not a problem. It's not a good way to go for a large project, and using extern and compiling each .c file separately is probably a "better practice" of course.
    Actually I'm pretty sure the "rule" is that each C file becomes an OBJ file, even in multi-compilers like VC++ you still end up with multiple .obj files... which are then linked into the executable. That would indicate that at compile time, each C file is considered a separate entity and thus multiple --unconnected-- copies of the variable would be created. This would also be born out by the behaviour our friend is describing... Moreover; if the compiler just mushed it all together, we would not need .h header/include files.

    I seriously doubt that listing all the files on a single command line changes that.

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by CommonTater View Post
    I seriously doubt that listing all the files on a single command line changes that.
    Here:

    main.h
    Code:
    int X;
    
    int getX(); 
    main.c
    Code:
    #include <stdio.h>
    #include "main.h"
    
    int main(void) {
    	int i;
    
    	X = 10;
    
    	for (i = 0; i<10; i++) {
    		printf("%d\n", getX());
    		X++;
    	}
    
    	return 0;
    }
    two.c
    Code:
    #include "main.h"
    
    int getX() { return X; } 
    // you can do whatever to X here as well, it is a singular global
    [root~/C/tmp] gcc -Wall main.c two.c
    [root~/C/tmp] ./a.out
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    Again, not a best practice, but it does work. I'm not sure what the standard says about this so it may differ from compiler to compiler.
    Last edited by MK27; 06-23-2011 at 10:06 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Quote Originally Posted by MK27 View Post
    Here:

    main.h
    Code:
    int X;
    
    int getX(); 
    main.c
    Code:
    #include <stdio.h>
    #include "main.h"
    
    int main(void) {
    	int i;
    
    	X = 10;
    
    	for (i = 0; i<10; i++) {
    		printf("%d\n", getX());
    		X++;
    	}
    
    	return 0;
    }
    two.c
    Code:
    #include "main.h"
    
    int getX() { return X; }
    [root~/C/tmp] gcc -Wall main.c two.c
    [root~/C/tmp] ./a.out
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    Again, not a best practice, but it does work. I'm not sure what the standard says about this so it may differ from compiler to compiler.
    I'll bet you a nickel that you now have two .o files in that directory. And also, if you put int X=5 in your two.c file you'd get different answers.

    EDIT: Nope, I'm wrong. GCC doesn't write out separate .o files here. (I think I used to know that, but then I forgot.) I'm pretty sure the rules for separate compilation are still followed.
    Last edited by tabstop; 06-23-2011 at 10:22 AM.

  11. #11
    Astrophysics student Ayreon's Avatar
    Join Date
    Mar 2009
    Location
    Netherlands
    Posts
    79
    Ok, now i'm getting a multiple definition error. This might be due to the inclusion of the .h files in several .c files, but if I don't do that it tells me the variables I want to use are not declared.
    I'll give a few pieces of the code, maybe that'll help:
    The last .c file has the error (the variable is nowhere else defined but in the constants.h).

    main.c:
    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    
    #include "constants.h"
    #include "constant_calculations.h"
    #include "initial_value_calculator.h"
    
    int main(){
    
      double f0_GW, r0, phi0, pr0, pphi0, m1, m2 ;
      double EOB_M, nu, v_MECO, v_pole, c_array[6], omega0;
    
      m1 = 1.0*phys_MO ;
      m2 = 1.0*phys_MO ;
      EOB_M  = m1 + m2 ;
      nu = m1*m2*pow(EOB_M,-2) ;
      v_MECO = calculate_vMECO(EOB_M) ;
      v_pole = calculate_vpole(nu) ;
      fill_c_array() ;
    
      //more stuff..
    
      return 0 ;
    }
    constants.h:
    Code:
    double const phys_MO = 4.94296E-6 ;
    
    extern double c_array[6] ;
    
    extern double EOB_M, nu;
    extern double v_MECO, v_pole ;
    extern double omega0;
    constant_calculations.c:
    Code:
    #include <stdlib.h>
    #include <math.h>
    
    #include "constants.h"
    
    double EOB_M, nu, v_MECO, v_pole, c_array[6], omega0;
    
    //functions including calculate_vMECO(EOB_M), calculate_vpole(nu) and fill_c_array()
    //fill_c_array() uses other functions which use nu inside (not in the arguments)
    initial_value_calculator.c:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    
    #include "constants.h"
    #include "hamiltons_equations.h"
    #include "reaction_force.h"
    
    double EOB_M, nu, v_MECO, v_pole, c_array[6], omega0;
    
    double z(double r, int diff) { //ERROR: It says at this line that it detects a multiple definition of 'phys_MO'
      double Ar,Ar_prime,X1,X2,dX1,dX2 ;
    
      Ar = calculate_Ar(r,0) ;
      Ar_prime = calculate_Ar(r,1) ;
      X1 = pow(r,3) * pow(Ar,2) ;
      X2 = pow(r,3) - 3*pow(r,2) + 5*nu ;
      dX1 = 2*pow(r,2)*pow(Ar,2) + 2*pow(r,3) * Ar * Ar_prime ;
      dX2 = 3*pow(r,2) - 6*r ;
    
      switch(diff) {
        case 1:
            return dX1/X2 - (X1/pow(X2,2)*dX2) ;
        default:
            return X1/X2 ;
      }
    }
    
    //more functions
    Nothing to see here, move along...

  12. #12
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    One time. If you don't put extern on it in the header, then you're declaring it a lot of times -- one time every time you #include the header.

  13. #13
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Let's consider one of the variables, EOB_M.

    First, you declare it extern in "constants.h", so it needs to be declared globally in one other place. That's not what you have. Instead, you declare locally in main(), and then again, globally, in initial_value_calculator.c. So most of the other c files will be using the "EOB_M" from initial_value_calculator, but this is no doubt complicated by the fact that there is another EOB_M local to main().

    As Common Tater says, what you want is this:

    constants.h
    Code:
    #ifndef VAR_EOB_M
    extern double EOB_M;
    #define VAR_EOB_M
    #endif
    I used the include guards because you do not want this used in the file where EOB_M is actually declared without extern. That should be GLOBAL, but not in a file included in any other file (ie, a .c file, or a .h used by only one .c):

    Code:
    double EOB_M;
    #define VAR_EOB_M;
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  14. #14
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by tabstop View Post
    I'll bet you a nickel that you now have two .o files in that directory. And also, if you put int X=5 in your two.c file you'd get different answers.
    Nope. I guess this really is an unusual thing to do. Anyway:

    main.h
    Code:
    int X;
    
    int getX();
    void initX();
    main.c
    Code:
    #include <stdio.h>
    #include "main.h"
    
    int main(void) {
    	int i;
    
    	initX();
    
    	for (i = 0; i<10; i++) {
    		printf("%d\n", getX());
    	}
    
    	return 0;
    }
    two.c
    Code:
    #include "main.h"
    
    void initX() {
    	X = 5;
    }
    
    int getX() { 
        X++;
    	return X; 
    }
    [root~/C/tmp] gcc -Wall main.c two.c
    [root~/C/tmp] ls
    a.out main.c main.h two.c

    [root~/C/tmp] ./a.out
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15

    I used to compile things this way all the time before I learned to use "make" properly; instead of a makefile I had a "compile.sh" with one long gcc call, lol. I think my first sourceforge project still works on this principle, just via autotools (ie, the makefile has only one target).

    Fool around with that as much as you like, X is definitely a singular global. Looks like I'm up by $0.05
    Last edited by MK27; 06-23-2011 at 10:28 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  15. #15
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Code:
    double const phys_MO = 4.94296E-6 ;
    
    extern double c_array[6] ;
    
    extern double EOB_M, nu;
    extern double v_MECO, v_pole ;
    extern double omega0;
    The multple definition error is probably coming from your first double const value...
    You can probably correct this with "Include Guards" in your header....

    Code:
    #ifndef CONSTANTS_H
    #define CONSTANTS_H
    
    double const phys_MO = 4.94296E-6 ;
    
    extern double c_array[6] ;
    
    extern double EOB_M, nu;
    extern double v_MECO, v_pole ;
    extern double omega0;
    
    #endif  //CONSTANTS_H
    This will prevent your header file from being read more than once in each compilation unit.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. creating variables inside an if statement
    By nik in forum C++ Programming
    Replies: 3
    Last Post: 03-21-2011, 03:41 PM
  2. Replies: 30
    Last Post: 06-19-2006, 12:35 AM
  3. Replies: 5
    Last Post: 10-23-2005, 08:33 PM
  4. variables inside class help
    By Rune Hunter in forum C++ Programming
    Replies: 12
    Last Post: 10-02-2005, 09:15 AM
  5. Variables in a header file
    By Crossbow in forum C++ Programming
    Replies: 4
    Last Post: 03-29-2002, 11:54 AM

Tags for this Thread