Where does a function declared in .h file find the its definition?

Viewed 1213

I'm new to C programming and I have questions about the header files inclusion part.

(1) I know that by convention, a header file shouldn't include function definitions. But in this simple code:

#include<stdio.h>
int main(){
    printf("123");
}

printf function is declared in stdio.h, however I didn't manually define the printf function. Why does the code compile successfully? Shouldn't it throw a compilation error something like function printf is not defined?

(2) Suppose that I have a foo.h header file, which declares function foo

int foo(int num);

I have a main.c file below in the same directory as foo.h:

#include <stdio.h>
#include "foo.h"
int main(){
    printf("%d",foo(123));
}

My question is where should I define function foo? Is there any other place besides inside main.c?

If not, what's the point of using header files? Because in my mind, it's like: every time we want to implement a function declared in a header file, we have to define it in the .c file. Why not define (and thus declared) function foo in main.c, directly?

4 Answers

If not, what's the point of using header files? Because in my mind, it's like: every time we want to implement a function declared in a header file, we have to define it in the .c file. Why not define (and thus declared) function foo in main.c, directly?

Real projects can grow to have hundreds or even thousands of different functions and keeping them all in the same source file rapidly becomes untenable. Instead, we group them into separate source files that can be compiled independently into object files (machine code, but not executable on their own), and then those object files can be linked into an executable file (or a library that can be linked into other projects, such as the standard C libraries).

Separate compilation has a number of benefits:

  • Different parts of an application can be tested independently of each other;
  • Code can be easily shared between different projects;
  • Parts of an application can be re-implemented without affecting other parts.

You must declare a function before you call it so the compiler can determine that you're calling the function correctly (passing the right number and types of arguments and using the result appropriately). If the function is defined in a different source file from the caller, it’s often a good idea to put the declaration in a separate header, so instead of manually retyping the declaration in every source file that calls that function, you just #include the header file containing that declaration.

It's also common to define new types (such as the FILE type) and macros (such as the NULL macro) in header files so those definitions can easily be #included and used by your code.

It’s kind of hard to see the utility until you work on a sizable project.

The main purpose of header files is to declare functions and variables defined in one module to be used in another unrelated module.

In your second example, you could create foo.c with the following contents:

int foo(int num)
{
    return num * 4;
}

Then you would compile both foo.c and main.c:

gcc -c foo.c
gcc -c main.c

Then link them:

gcc -o my_program foo.o main.o

If you tried to compile and link only main.c, you'd get a linker error stating that the definition of foo could not be found.

When you have a large project, you'll typically want to break up functions into multiple files, with related functions together in one .c file.

For functions declared in stdio.h, these are part of the standard C library. The definitions for these functions are automatically linked in so you don't have to do so explicitly.

Why does the code compile successfully?

Because your compiler automatically links standard C library. The standard C library contains the definition of printf function.

Shouldn't it throw a compilation error something like function printf is not defined?

No, the compiler is required to provide definitions for standard symbols and printf is one of them (in a hosted environment).

My question is where should I define function foo?

Anywhere you want. In main.c or in another .c file you want. Typically, a good practice, I would expect foo to be defined in foo.c, because it's declaration is in foo.h.

Is there any other place besides inside main.c?

Yes, in another translation unit - in another .c file. For example in foo.c.

If not, what's the point of using header files?

A long, long time ago computers weren't as fast as they are today - but still these computers had C language. Because it was impossible for historic compilers to parse all function definition in one big file, because for example of limited memory available at that time, for speed of compilation defining a symbol was splitted into smaller units. Symbol declaration were placed in one file, definitions in another. That way compilers compile small .c files that see only short .h files containing only smaller amount of information, then after compiling it in a separate stage the linker links all pre-compiled .c files together. That way compilation uses less resources at a time.

Nowadays, newer progarmming languages just don't care - when you write like import in these languages the compiler works as-if it extracts declarations from definitions. Computer are fast and powerful enough to handle that with ease. With newest addition of modules in C++, the C++ community is hoping to get a similar mechanisms.

Why not define (and thus declared) function foo in main.c, directly?

Dividing symbols definitions between source files is a matter of quality. We programmers divide information into smaller pieces and place them in separate files to easier manage big programs. But, sure, why not - if it's a small program, just do it in a single file, there are many programs written in a single .c file (that is very long, ex. more then 3000 lines).

printf function is declared in stdio.h, however I didn't manually define the printf function. Why does the code compile successfully? Shouldn't it throw a compilation error something like function printf is not defined?

Compiler emits the code which calls the printf. It does not check if the function is in other compilation units or object files. The compiler has only to know what the printf is - ie what is the return type and the parameters of the function. Later the linker links the object files and libraries and finds if the printf is somewhere there. Because you link towards the standard library - the compiled printf function is there and the linking is successful. If linker will not find the function (or generally object) in the object files and libraries, it will emit an error.

My question is where should I define function foo? Is there any other place besides inside main.c?

Anywhere. In any compilation unit. The important part is that the generated object file containing foo code (definition) has to passed to the linker.

If your function has not external linkage (ie is declared as static) its definition has to be in the same compilation unit (file) as the calling function.

Example:

static void foo(int n);

int main(void)
{
    foo(123);
}

static void foo(int n)
{
    printf("%d\n", n);
}
Related