Thread: how to use one .c file variable in another .c file

  1. #1
    Registered User
    Join Date
    Feb 2010
    Posts
    50

    how to use one .c file variable in another .c file

    I have a file file2.c containing a table:

    Code:
    struct table_row { int int_var; char *char_array1; char *char_array2; };
    
    struct table_row a_table[] = {
       1, "row 1, column 2", "row 1, column 3",
       2, "row 2, column 2", "row 2, column 3"
       0, NULL, NULL
    };
    and I would like to use this table variable a_table in another file file1.c. How can I accomplish this?

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by nicoeschpiko
    and I would like to use this table variable a_table in another file file1.c. How can I accomplish this?
    Pass the variable, or a pointer thereof, or in this case a pointer to the first element of the array, to the function(s) defined in file1.c.

    murugaperumal's example proposes the use of a global variable, but you should ignore that option for the time being. The example is problematic anyway as it incorrectly defines the global variable in the header file instead of say, declaring it extern.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    #including .c files is generally a bad thing to do. Instead:

    whatever.h
    Code:
    struct foo { int x; };
    
    extern struct foo a[];
    file1.c
    Code:
    #include "whatever.h"
    
    struct foo a[] = { ... };
    file2.c
    Code:
    #include "whatever.h"
    
    /* now you can use “a” here */
    The idea is this: You define your object in exactly one .c file. You then use “extern” from another file to gain access to it. The extern means, roughly, “this is defined elsewhere”. Without the extern, you're actually creating the object.

    The problem with including .c files is that it tends to lead to multiple definition errors. If you define something in a .c file (which is what tends to happen) and then include that in two other files, you'll have two definitions: not good!
    Last edited by cas; 03-13-2010 at 04:08 AM. Reason: A quote character got turned into a 'c'.

  4. #4
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    Thanks everyone for the wonderful discussion and guidance. Much appreciated!

  5. #5
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    One last question:

    How/where would i declare a variable (either in whatever.h or file1.c from the most recent post above), say called INTCONST which is equal to 5, that can be used in file2.c and file1.c?

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by nicoeschpiko
    How/where would i declare a variable (either in whatever.h or file1.c from the most recent post above), say called INTCONST which is equal to 5, that can be used in file2.c and file1.c?
    You would declare it as extern in the header, then define it in one of the source files. cas already described this.

    If INTCONST is really supposed to be a constant, then fine; you also have the option of defining it as a macro in the header. But if it is supposed to be a non-constant variable, then I suggest that you reconsider before you use such a global variable.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    I now have the following files:

    file2.h
    Code:
    struct line { char *string_var; int some_const; };
    
    extern int CONST_1;
    extern int CONST_2;
    extern int CONST_3;

    file2.c
    Code:
    int CONST_1 = 1;
    int CONST_2 = 2;
    int CONST_3 = 3;
    
    struct line table_of_lines[] = {
       "string1", CONST_1,
       "another_string1", CONST_1,
       "string3", CONST_3,
       NULL, 0
    };
    and i would like to be able to use CONST_1, CONST_2 & CONST_3 outside of file2.h. The error that I get when I compile is:

    file2.c:6: error: initializer element is not constant
    file2.c:6: error: (near initialization for 'table_of_lines[0].some_const')
    .
    .
    .
    file2.c:8: error: (near initialization for 'table_of_lines[2].some_const')

    even when i put the const keyword in front of int CONST_1 in file2.c and file2.h, I still get the same error. How can I use this integer value in my array in file2.c and in other files?

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Because you redefined them in file2.c. This is very simple -- and nb, the term "extern" is almost always superfluous:

    header.h
    Code:
    const int Somenum;
    Any file which includes the header will now also include global variable Somenum, eg.

    whatever.c
    Code:
    #include "header.h"
    
    int main() {
         Somenum = 5;
    }
    Notice I did not redeclaree Somenum again!

    Of course, your problem is now that Somenum is declared const, meaning you have to give it a value.
    Code:
    const int X;
    is basically useless, unless you just want X to be 0 (the default for global variables, since you cannot assign a value to a const after declaration. If you want it to be const, define it in the declaration:
    Code:
    const int X = 666;
    If you don't want to do that, do not declare it const! If you need to use it like a const, just cast:
    Code:
    somefunct((const int)X);
    And as laserlight pointed out, global consts are usually better as #defines.
    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

  9. #9
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    the term "extern" is almost always superfluous:
    This is not true. The basis for the requirement for extern can be found in section 6.9 of C99:
    An external definition is an external declaration that is also a definition of a function (other than an inline definition) or an object. If an identifier declared with external linkage is used in an expression (other than as part of the operand of a sizeof operator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier
    This is not a constraint, so any violation is undefined behavior which, of course, includes the possibility of “working”. The problem here is the text “there shall be exactly one external definition”. If you don't use extern, each inclusion of the header file creates an external definition. Two (or more) inclusions means multiple definitions, which is undefined.

    While this may work on some systems, there are others where it won't. Turbo C, for example, gives me the following error:
    Error: _foo defined in module file1.c is duplicated in module file2.c

    foo being the object that I neglected to use extern with. Changing the header to use extern and putting a definition in file1.c caused the error to disappear.

  10. #10
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    I did want a global const, so I took laserlight's advice of implementing the #define. Now I have:

    file2.h
    Code:
    struct line { char *string_var; int some_const; };
    
    extern CONST_1;
    extern CONST_2;
    extern CONST_3;
    file2.c
    Code:
    #define CONST_1 1;
    #define CONST_2 2;
    #define CONST_3 3;
    
    struct line table_of_lines[] = {
       "string1", CONST_1,
       "another_string1", CONST_1,
       "string3", CONST_3,
       NULL, 0
    };


    And this is able to compile without error. Thanks!

    I am now trying to use these values in a switch statement like so:

    file1.c
    Code:
    #include <stdio.h>
    #include "file2.h"
    
    int main() {
       int index;
       for (index=0; table_of_lines[index].string_var; index++) {
          switch(table_of_lines[index].some_const) {
             case CONST_1:
                printf("String of kind 1: %s\n", table_of_lines[index].string_var);
                break;
             case CONST_1:
                printf("String of kind 2: %s\n", table_of_lines[index].string_var);
                break;
             case CONST_1:
                printf("String of kind 3: %s\n", table_of_lines[index].string_var);
                break;
          }
       }
    }

    and i am getting errors for these variables that say:
    file1.c... error: case label does not reduce to an integer constant
    file1.c... error: case label does not reduce to an integer constant
    file1.c... error: case label does not reduce to an integer constant



    or if I just try to use one of these variables in file1.c
    Code:
    #include <stdio.h>
    #include "file2.h"
    
    int main() {
       printf("%d\n", CONST_1);
       return 0;
    }
    , I get:
    undefined reference to 'CONST_1'
    Last edited by nicoeschpiko; 03-13-2010 at 06:54 PM.

  11. #11
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    For the LAST time:

    DO NOT DECLARE A VARIABLE MORE THAN ONCE.

    If you want to declare it in the header, declare it in the header. If you declare it again after that, you have problems.

    Do not declare a #define extern either. Other than that, cas's point is a good one if for some reason you could end up including the header multiple times.

    However, if you do declare it extern in the header, then do declare it there twice:

    header.h
    Code:
    extern int X;
    int X;
    This is because headers are usually associated with a pre-compiled object which defines the declarations in the header. Since you are not doing that, you have to compensate. You could also just declare it in main.c again (but in that case, don't declare it extern the 2nd time).

    Or, you could just:

    1) not use extern
    2) only include the header ONCE.
    Last edited by MK27; 03-13-2010 at 07:26 PM.
    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

  12. #12
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    if i only declare the variable in the header file2.h as:

    Code:
    struct line { char *string_var; int some_const; };
    
    extern int CONST_1 = 1;
    extern int CONST_2 = 2;
    extern int CONST_3 = 3;
    and remove it from file2.c
    Code:
    #include "file2.h"
    
    struct line table_of_lines[] = {
       "string1", CONST_1,
       "another_string1", CONST_1,
       "string3", CONST_3,
       NULL, 0
    };
    I still get the errors:
    file2.h:...warning: 'CONST_1' initialized and declared 'extern'
    .
    .
    .
    file2.h:...warning: 'CONST_2' initialized and declared 'extern'
    file2.c:6: error: initializer element is not constant
    file2.c:6: error: (near initialization for 'table_of_lines[0].some_const')
    .
    .
    .
    file2.c:8: error: (near initialization for 'table_of_lines[2].some_const')



    This example is about ten lines. Is there a concise postable solution to this for the two file2.* files where the variables CONST_# can be used in a file1.c directly?

  13. #13
    Registered User
    Join Date
    Feb 2010
    Posts
    50
    I noticed that when i only have the #defines in the header, and nowhere else, everything compiles fine. I can also properly use the variables in both the corresponding .c file, and any other c file. The variables are also usable in the switch statement.

  14. #14
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Yeah, defines are probably the way to go here. The thing with using "extern" which makes it a hassle:

    - you cannot initialize the variable in the declaration
    - the variable must be declared again somewhere else.

    Basically, the situation cas was talking about is one which may occur with a library header -- when you want to be able to include a header multiple times safely.

    However, IMO it is also important to understand how to write an include that is only used once, and how to compartmentalize code that way without redefining things accidentally or creating other screw-ups. As a beginner, you will probably have more of a need to do that than to compile libraries and write headers for them.

    When people remark that "it is bad to include a .c file", etc, they are kind of avoiding independent thought or responsibility in favour of reciting liturgy. It is like saying: because you can exceed the bounds of an array, you should not use arrays.

    If you understand what you are doing, you can use arrays without going out of bounds, and you can include one .c source in another.
    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
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Basically, the situation cas was talking about is one which may occur with a library header -- when you want to be able to include a header multiple times safely.
    No, I'm talking about sharing a global variable between multiple source files in a single project. If you are only including a .h file in one .c file, you can act as though you're just writing for that single .c file, because you in essence are. But as soon as you use the .h in multiple .c files, you have to be more careful. While there certainly are uses for including a .h file in a single source file, and there are uses for putting object/function definitions inside of a .h file (inline functions, tables generated at build-time, etc), it is very common to have a shared .h file—even if you're not writing a library.
    When people remark that "it is bad to include a .c file", etc, they are kind of avoiding independent thought or responsibility in favour of reciting liturgy. It is like saying: because you can exceed the bounds of an array, you should not use arrays.
    I think this is disingenuous. First, as I explained, the issue with including .c files is the problem of multiple definitions. It's not a case of “don't include .c files”, it's a case of “including .c files is generally bad, and here's why.”

    I don't think it's analogous to the array case. It's perhaps closer to goto. There are many cases where goto can be used, but it's not a good idea (we have loop constructs, after all). But there are cases where goto might be the cleanest option. The same goes for including .c files (or more properly, putting definitions inside of #included files).

    If you have a project of any size at all, it will almost certainly be split up into multiple .c files. There's also going to be a good chance that you'll want to share some data between the source files. As an example, FreeBSD's ls has four source files: cmp.c, ls.c, print.c, and util.c.

    ls has an obscene number of flags (i.e. command-line options), some of which correspond to variables that need to be used in various source files. f_humanval, for example, is a boolean that controls whether to print values in human-readable form (e.g. 615M instead of 644448021). The file ls.c does command-line argument parsing, so it needs access to f_humanval in order to set/clear it as necessary. print.c, which handles the actual output, also needs access so it knows how to format sizes. ls is not a huge program, but it is split up four ways, and has multiple objects that are shared. This is not an uncommon approach; anything else would get unwieldy very fast.

    Again, I'm not arguing that it's never a good idea to define objects in source files. I have a project that uses two lookup tables that I've generated; each has 256 entries. I find it cleaner to put them in their own .h file and include them in the file that needs access to them (I've marked them as static for obvious reasons). No point in cluttering up my .c file with 512 random-looking hex values. The same project also has function definitions inside of a .h file; specifically, static inline functions. It'd be kind of tough to share inline functions without doing it this way. But this, I opine, is not the norm. More often than not you'll run into the case of FreeBSD's ls, where you simply want to share objects. This is achieved with a single .h file, with no definitions, included in multiple .c files.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Formatting a text file...
    By dagorsul in forum C Programming
    Replies: 12
    Last Post: 05-02-2008, 03:53 AM
  2. Need some help...
    By darkconvoy in forum C Programming
    Replies: 32
    Last Post: 04-29-2008, 03:33 PM
  3. Formatting the contents of a text file
    By dagorsul in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2008, 12:36 PM
  4. C++ std routines
    By siavoshkc in forum C++ Programming
    Replies: 33
    Last Post: 07-28-2006, 12:13 AM