Compiling multiple C files in a program

92,156

Solution 1

You don't need an extern, but file1.c must see a declaration that foo() exists. Usually this declaration is in a header file.

To add a forward declaration without using a header file, simply modify file1.c to:

int foo();  // add this declaration

int main(){
  foo();
  return 0;
}

Solution 2

The correct way is as follows:

file1.c

#include <stdio.h>
#include "file2.h"

int main(void){
    printf("%s:%s:%d \n", __FILE__, __FUNCTION__, __LINE__);
    foo();
    return 0;
}

file2.h

void foo(void);

file2.c

#include <stdio.h>
#include "file2.h"

void foo(void) {
    printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
    return;
}

output

$
$ gcc file1.c file2.c -o file -Wall
$
$ ./file 
file1.c:main:6 
file2.c:foo:6 
$ 

Solution 3

You can, but you shouldn't.

Use a header file, file2.h:

// file2.h

void foo(); // prototype for function foo()

Then add:

#include "file2.h" 

in file1.c

To compile:

$ gcc -Wall file1.c file2.c -o foo

As a general rule it's better (more robust) to use a header file to define the interface of each module rather than ad hoc prototypes within dependent modules. This is sometimes known as the SPOT (Single Point Of Truth) principle.

Solution 4

It's ugly, but using gcc, you could:

gcc -include file2.c file1.c

-include is a flag to the preprocessor which will include the contents of file2.c at the very top of file1.c. Having said that, it's a poor choice, and breaks down for all but the simplest of programs.

Share:
92,156

Related videos on Youtube

mary
Author by

mary

Updated on July 05, 2022

Comments

  • mary
    mary almost 2 years

    I have the following two files:

    file1.c

    int main(){
      foo();
      return 0;
    }
    

    file2.c

    void foo(){
    
     }
    

    Can I compile and link the two files together so the file1.c will recognize the foo function without adding extern?

    Updated the prototype.

    gcc file1.c file2.c throws: warning: implicit declaration of function foo.

    • Seth Carnegie
      Seth Carnegie over 12 years
      gcc file1.c file2.c, also I don't know C's exact rules for function calls when it's not seen a prototype but you might have to add int foo(); above main
    • Paul R
      Paul R over 12 years
      @Seth: please always -include -Wall when giving gcc examples - it helps to get noobs into good habits.
    • mary
      mary over 12 years
      I updated the question. I do it with -Wall.
  • mary
    mary over 12 years
    can I do it without any header files just by compiling the two together?
  • chrisaycock
    chrisaycock over 12 years
    You still need a forward declaration of foo(), which you could do in file1.c if you want.
  • Seth Carnegie
    Seth Carnegie over 12 years
    @mary yes, header files are for the compiler but this is done by the linker
  • Seth Carnegie
    Seth Carnegie over 12 years
    You don't need extern for calling a function, you only need the prototype, like int foo(); in the header and the body in file2.c
  • Paul R
    Paul R over 12 years
    @Seth: true - you don't need it, but there is nothing wrong with making it explicit.
  • Seth Carnegie
    Seth Carnegie over 12 years
    I've never seen anyone make a function extern just because it's in another file. Saying you can but shouldn't write a function in another file without using extern on the prototype is completely baseless, unless you know something I don't (which is likely)
  • Paul R
    Paul R over 12 years
    @Seth: not at all - the prototype is extern whether you explicitly declare it extern or use C's implicit rules. I put it there to make it clear for noobs that it's a prototype, but mostly people don't use the explicit extern declaration form these days.
  • Seth Carnegie
    Seth Carnegie over 12 years
    Then why do you tell him that he shouldn't write a function that is to be used in other files without writing extern? The word "shouldn't" is too strong here
  • Paul R
    Paul R over 12 years
    @Seth: if you want to encourage good software engineering practices then you need to promote separation of interface versus implementation for each module. I'll take the extern out of you prefer - it's only there for clarity but clearly it bothers you.
  • Seth Carnegie
    Seth Carnegie over 12 years
    I had no problem with the extern, it's telling someone what they should do here. As I said, I've never seen this before, ever. Have you? I don't see where should is backed up by anything. Usually when you tell someone what they should do, you also present reasons why they should, and I can't see any reason at all for this, not even "because everyone else does it"
  • Paul R
    Paul R over 12 years
    @Seth: I've added some clarification to justify the "should" - ad hoc prototypes really should be discouraged.
  • pmg
    pmg over 12 years
    The C99 pre-defined identifier is __func__. Prefer this to the gcc specific __FUNCTION__.
  • Timothy Jones
    Timothy Jones over 12 years
    I don't think it's good practice to pass the header to the compiler like that - if it's needed, the preprocessor will bring it in.
  • Seth Carnegie
    Seth Carnegie over 12 years
    Is there some external source that also advocates using extern on all prototypes? (i.e. that also says you should always use extern)
  • Sangeeth Saravanaraj
    Sangeeth Saravanaraj over 12 years
    @TimothyJones My apologies. That is a nice point. Thanks for keeping a check on the answer! .. I have corrected it now!
  • Paul R
    Paul R over 12 years
    @Seth: pretty much any decent introductory textbook on software engineering should cover this - I don't have a specific example at hand that I can cite though.
  • Paul R
    Paul R over 12 years
    Also please always include -Wall in any gcc command line example.
  • Minuet
    Minuet over 3 years
    @PaulR What's the -Wall for?
  • Paul R
    Paul R over 3 years
    @Minuet: it tells the compiler to enable all warnings - compiler warnings are really helpful and important, particularly for people who are still learning the language, but unfortunately they are not enabled by default, Always compile with warnings enabled and pay attention to any warnings that the compiler omits.