1

I've heard that you put function prototypes in header files and then put the function definitions in a .c file. However, what is this .c file. For example, if you were to include a file "foo.h", would you call the aforementioned .c file "foo.c", put the function definition in it, put it in the same place as the foo.h, and when you try to include foo.h, will the function carry over from the c file and will the function be ready to use?

  • 1
    The reason not to put functions in header files is that if you include it in two .c files, you will get two definitions of the function. – stark May 17 '18 at 19:33

2 Answers2

3

No, just putting the .c with the .h and including it in your code doesn't magically carry over the definition of the functions too.

You need to compile the foo.c separately into an object file (in case of Linux, it is a .o file). For example using the command -

gcc -c foo.c -o foo.o

Now this foo.o needs to be linked to your actual program. This can be done by simply passing the object file while compiling as

gcc test.c foo.o -o test.out

If you do not link the foo.o with your program, your linker won't be able to find the implementations for the functions defined in it and will throw a linker error as -

Undefined reference to function foo_function.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • Thanks for your helpful answer! Just one more question: in the foo.c, do you have to include the foo.h, or do you just define the function with no mention of the header? –  May 17 '18 at 19:49
  • 1
    @J.S. It is usually a good idea to include the headers in the corresponding `.c` too so that the types in the headers match the types in the definition. If they are different by mistake, the compiler will report an error. – Ajay Brahmakshatriya May 17 '18 at 19:57
  • OK, thanks for all your help, I really appreciate it :) –  May 17 '18 at 20:05
  • 1
    @J.S. I would go a little farther than "usually a good idea" and say, "Yes, you have to". It will work without it, it's true, but it opens up a huge hole in the type-checking system. (Me, I wish compilers would complain about functions being defined without a prototype in scope, just as they complain about functions being called without a prototype in scope.) – Steve Summit May 17 '18 at 21:46
  • 1
    Modern GCC does complain a lot more about functions called without a declaration in scope — GCC compilers version 5.0 and later use C11 mode by default. They still don't automatically complain about no prototype; you can enable that with `-Wstrict-prototypes` (which is not a part of `-Wall` or `-Wextra`, to my considerable surprise). There's also `-Wold-style-definition` and `-Wold-style-declaration` and `-Wmissing-prototypes`. – Jonathan Leffler May 18 '18 at 04:27
  • I recommend passing at least `-Wall -Wextra -g` to `gcc` and probably `-Wstrict-prototype` also – Basile Starynkevitch May 18 '18 at 05:08
  • @For those interested in this subtopic, see [this other question](https://stackoverflow.com/questions/50401100/compiler-warning-for-function-defined-without-prototype). – Steve Summit May 18 '18 at 11:13
  • @J.S. As others have clarified it, including the header is essential. Infact on many systems, the linker does not (and cannot) check for type mismatch because of lack of a proper name mangling scheme. – Ajay Brahmakshatriya May 18 '18 at 11:15
1

Header files are just conventional. The C preprocessor is handling #include directives and the compiler sees the preprocessed input (but you might copy and paste huge amount of C code to get the equivalent of #include). Actually, the preprocessor don't care if you #include "foo.h" or #include "foo.c", but the later is often poor taste. Naming header files with a .h suffix is just a (very common) convention.

So, if you have a function definition in a header included in several source files (technically translation units), that function definition is in every such translation unit.

What happen then depends on that function definition (it should be static or even better static inline).

In practice, you should restrict function definitions in header to be static or static inline. If you don't declare static a function definition void foo(int x) { /* something */ } in a header which is included in several *.c files you'll have multiple-definitions of foo errors at link time. And the main interest of putting a function definition in a header is to enable inlining (hence the inline hint); otherwise (the usual case), you don't need that and you just put the function prototype in the header file and the function definition in one of your *.c files.

If you have short and quick running functions, it could be wise to define them as static inline (so give their bodies) in your header files (but of course, that increases the compilation time). Otherwise, it is not worth the burden.

Some header files might have long macros (of dozens of physical lines, all of them except the last ended with a backslash) expanded to function definitions. Look into sglib for an example.

Notice that inline is today (like register was in the previous decade) just a hint to the compiler (for inline expansion optimization), which is allowed to ignore it (also, many optimizing compilers are able to inline functions without any annotation, provided they know the body of the called function).

Don't forget to enable all warnings and debug info. With GCC, use gcc -Wall -Wextra -g, perhaps with -Wstrict-prototypes. You could get the included files with -H (and the preprocessed form with -C -E).

Refer to some C reference site and to the C11 standard n1570 for more details. Read the GNU cpp reference manual about preprocessing.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547