24

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.

nbro
  • 15,395
  • 32
  • 113
  • 196
mary
  • 869
  • 5
  • 13
  • 26
  • 2
    `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` – Seth Carnegie Jan 04 '12 at 14:48
  • @Seth: please always -include `-Wall` when giving gcc examples - it helps to get noobs into good habits. – Paul R Jan 04 '12 at 14:54
  • I updated the question. I do it with -Wall. – mary Jan 04 '12 at 14:55

4 Answers4

51

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 
$ 
Sangeeth Saravanaraj
  • 16,027
  • 21
  • 69
  • 98
  • 1
    The C99 pre-defined identifier is `__func__`. Prefer this to the gcc specific `__FUNCTION__`. – pmg Jan 04 '12 at 15:18
  • 1
    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. – Timothy Jones Jan 04 '12 at 15:18
  • @TimothyJones My apologies. That is a nice point. Thanks for keeping a check on the answer! .. I have corrected it now! – Sangeeth Saravanaraj Jan 04 '12 at 15:22
  • 1
    Also please always include `-Wall` in any gcc command line example. – Paul R Jan 04 '12 at 15:23
  • @PaulR What's the -Wall for? – Minuet Nov 19 '20 at 15:29
  • 2
    @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. – Paul R Nov 19 '20 at 15:31
8

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;
}
chrisaycock
  • 36,470
  • 14
  • 88
  • 125
7

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.

Paul R
  • 208,748
  • 37
  • 389
  • 560
  • 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` – Seth Carnegie Jan 04 '12 at 15:00
  • @Seth: true - you don't *need* it, but there is nothing wrong with making it explicit. – Paul R Jan 04 '12 at 15:02
  • 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) – Seth Carnegie Jan 04 '12 at 15:04
  • @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. – Paul R Jan 04 '12 at 15:05
  • 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 – Seth Carnegie Jan 04 '12 at 15:06
  • @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. – Paul R Jan 04 '12 at 15:08
  • 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" – Seth Carnegie Jan 04 '12 at 15:13
  • @Seth: I've added some clarification to justify the "should" - *ad hoc* prototypes really should be discouraged. – Paul R Jan 04 '12 at 15:16
  • Is there some external source that also advocates using `extern` on all prototypes? (i.e. that also says you should always use `extern`) – Seth Carnegie Jan 04 '12 at 15:20
  • @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 Jan 04 '12 at 15:22
  • 1
    Note that until you are using C23, the line `void foo(); // prototype for function foo()` in `file2.h` provides a declaration of fucntion `foo()` but does NOT provide a prototype for the function. The empty parentheses say "takes an undefined list of arguments, but is not a variadic function (like `printf()` — there is no `, ...` at the end of the prototype)". Providing a declaration is sufficient to allow the function to be called in C99, C11, C18. – Jonathan Leffler Dec 16 '22 at 23:02
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.

Dave
  • 10,964
  • 3
  • 32
  • 54