Separate Compilation

Big software projects are typically split among multiple files. Helper functions might be separated from main, grouped together as a library of functions which accomplish related tasks using header files.

Header Files

Header files specify declarations and a separate .c source file will contain definitions for those functions declared in a .h header file.

Different files used within one program communicate using header files (.h files) to group declarations, then #include them into appropriate files. There are two ways to include files:

When the pre-processor sees a #include directive, it inserts the content of the specified files at that location in the code.

function.c:

#include "functions.h" //including my own header file (use " ")

float func1 (int x, float y) {
	return x+y;
}

int func2 (int a) {
	return 2*a;
}

function.h:

float func1 (int x, float y);
int func2 (int a);

mainFIle.c:

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

int main() {
	printf("%.f %d", func1(2,3.0), func2(7));
	return 0;
}

You must compile both of the c files by gcc mainFile.c function.c.

Compilation and Linking


Compiling translates source files (.c files) into intermediate object files.

Linking combines .o files into one executable file called a.out.

This is an advantage because by compiling separately you don't need to compile every single file, which could be hundreds. You only need to compile the .c file that you changed and link the files together.

Header Guards

Always include header guards when making our own .h files that include definitions. They prevent compile time error by preventing definition duplication when multiple .c files include the same .h file.

Example header guard for a file named rectangle.h:

// change the all-caps name to match the file name
// in this case, file is named rectangle.h
#ifndef RECTANGLE_H 
#define RECTANGLE_H

struct rectange {
	int height;
	int width;
};

#endif

If a.h includes b.h, and main.c includes a.h and b.h, then b.h is included twice, causing an error. Header guards prevent this.

make and Makefile

make is an automated building tool helps you keep track of which files have been changed and need to be` recompiled. This saves time, avoids headaches from forgetting to recompile code, and reduces typing.

To use, make a configuration-type file called Makefile (or makefile). Specify which files depend on which other files, and which command should be used to create them.

There are many strict rules:

Example

Makefile:

CC=gcc
CFLAGS=-std=c99 -pedantic -Wall -Wextra

main: mainFile.o functions.o
	$(CC) -o main mainFile.o functions.o

mainFile.o: mainFile.c functions.h
	$(CC) $(CFLAGS) -c mainFile.c

functions.o: functions.c functions.h
	$(CC) $(CFLAGS) -c functions.c

clean:
	rm -f *.o main

Commands to type at command prompt:

make functions.o or make mainFile.o

make main

make

make clean

Others

If the compiler is trying to compile main, then the compiler does not need the full function definition in order to produce the object file(s). If you are trying to compile the functions itself, you need the full definition to create the object file.

sizeof() is an operator, and not a function, and it returns an unsigned integer, which can be printed with %lu. Find the size of an array by doing sizeof(array)/size(type)