By now you might have noticed that our programs are becoming larger. At some point they would become unwieldy to work on in a single file. It’d be nice to separate our program out into multiple code files that all link together, so working on different sections of code becomes less cumbersome.
There are many different ways you might elect to divide your code over different files, some more effective or useful than others. But it does come down to being more of an art than a science most of the time. One common way is to separate our code based on what it is supposed to do. For example, if you needed a lot of different math functions for a video game, you might put all of those math functions in one file, while putting all of your graphics code in another file, and your physics code in ANOTHER file.
Suppose we have a program that looks like this:
//main.c file
#include<stdio.h>
float Average(float a, float b)
{
float avg = (a + b) / 2.0f;
return avg;
}
int main()
{
printf("Input two numbers to average:\n");
float x, y;
scanf("%f%f", &x, &y);
float z = Average(x, y);
printf("The average of the two numbers is %f", z);
}We have an Average function, and all it does is find the average of two floats… cool. But maybe we decide that our Average function should go in a different file. OK, how do we start to do this? Let’s try to just copy/paste it over to another file and see if it just works. We’ll call this new file Average.c.
Here’s our main.c file:
//main.c file
#include<stdio.h>
int main()
{
printf("Input two numbers to average:\n");
float x, y;
scanf("%f%f", &x, &y);
float z = Average(x, y);
printf("The average of the two numbers is %f", z);
}And our Average.c file:
//Average.c file
float Average(float a, float b)
{
float avg = (a + b) / 2.0f;
return avg;
}But if we try to compile our code, we’ll get an error that looks something kinda like this:
error LNK2019: unresolved external symbol _Average referenced in function _main
This is what is known as a LINKER error!
As an aside to be clear, this is NOT the same thing as a compiler error (more on the differences below).
Compiler Errors vs Linker Errors
A compiler error happens when the SYNTAX of your program is incorrect; that is, the compiler doesn’t know how to translate your code into machine code due to a mistake in your code.
Analogy: you write a book and send it to your editor. Your editor sends the book back with red pen all over the pages: you accidentally misspelled several words, made jumbled run-on nonsense sentences, and put a question mark in the middle of a sentence.
A linker error happens when the Linker can’t stitch all the different parts of your program together in a way that makes sense. That is, your code references a function, but the Linker can’t find it.
Analogy: the editor OK’d your book, so now it’s been sent to your publisher. The publisher needs to put the chapters together in order, and your table of contents specified 15 chapters… but you forgot to label some of the chapters with a number! Even though there aren’t any spelling/grammatical errors, we don’t know how to put the book in order, or if some chapters might be missing!
OK great, different kinds of errors. How do we FIX this stuff?
Turns out we need to do something that might look a bit odd at first: we need ANOTHER new file!
Here’s our main.c file:
//main.c file
#include<stdio.h>
//Whoa, this line right here is NEW AND SHINY!
#include"Average.h"
int main()
{
printf("Input two numbers to average:\n");
float x, y;
scanf("%f%f", &x, &y);
float z = Average(x, y);
printf("The average of the two numbers is %f", z);
}Our Average.c file:
//Average.c file
float Average(float a, float b)
{
float avg = (a + b) / 2.0f;
return avg;
}And our NEW file, Average.h:
//Average.h file
float Average(float a, float b);So what the heck is goin’ on here? The issue is, we need a way for the Linker to know how to stitch our program together. So we’ve provided a Header file, which is the new Average.h file above. We put in some info about the function that is in our Average.c file. We ALSO added a line of code to our main.c file:
//The new line of code we added in main.c
#include"Average.h"This looks like the #include stuff we use to get printf to work… and it is! This is how we tell the Linker that we have some functions we compiled somewhere else, and we need to reference those functions in our main.c file.
But that might raise some questions. Why do need this new Header file thingy? Can’t we just use something like… this?
//Including a c file instead of a header file... yikes
#include"Average.c"Technically, YES, we can. But you should basically NEVER do this… why?
Functions: Definitions vs Declarations
THIS SECTION UNDER MAINTENANCE!
For now, know that the Average.h Header file needs a declaration:
//Note the semicolon at the end
float Average(float a, float b);And the Average.c file needs a definition:
//No semicolon, and the function body is present
float Average(float a, float b)
{
float avg = (a + b) / 2.0f;
return avg;
}