Chapter 24
Beyond Mere Mortal Projects
In This Chapter
Building big programs
Combining multiple source code files
Making your own header file
Linking in additional libraries
Not every C program you write will have only 20 or 30 lines of code. Most of the programs, the ones that truly do something, are much longer. Much, much longer. Some become so huge that it makes sense to split them into smaller modules, or individual source code files, with maybe 20 to 60 lines of code apiece. Not only do these smaller modules make it easier to write and update code, but you can also reuse common modules in other projects, reducing development time.
The Multi-Module Monster
The C language places no limit on how long a source code file can be. Likewise, a source code file can consist of only a few lines — if you can pull off that trick. The determination of whether to use multiple source code files — modules — really depends on the programmer. That’s you. How easy do you want to make the process or writing, maintaining, and updating your code?
Linking two source code files
The most basic multi-module monster project has two source code files. Each file is separate — written, saved, and compiled individually — but eventually brought together as one unit by the linker. The linker, which is part of the build process in Code::Blocks, is what creates a single program from several different modules.
What’s a module?
A module is a source code file and its compiled object file. Together, the source code and object files are what I call a module. Then the various object files are linked to build a program. The entire operation starts with separate source code files. See Listing 24-1.
Listing 24-1: The main.c Source Code File
#include <stdio.h>
#include <stdlib.h>
void second(void);
int main()
{
printf("Second module, I send you greetings!\n");
second();
return 0;
}
Exercise 24-1: Fire up a new project in Code::Blocks named ex2401. Create the project as you normally would: Type the source code from Listing 24-1 into the editor as the contents of the main.c
file. Save the file.
Don't build yet! After all, the code references the second()
function, which doesn't seem to exist anywhere. It's prototyped, as is required for any function that's used in your code, but the second()
function is found in another module. To create that module in Code::Blocks, follow these steps:
1. Save the current project, ex2401.
2. Choose File⇒New⇒Empty File.
3. Click the Yes button when you’re prompted to add the file to the active project.
The Save File dialog box appears.
4. Type alpha.c as the filename and then click the Save button.
The new file is listed on the left side of the Code::Blocks window, beneath the Sources heading where the main.c
file is listed. A new tab appears in the editor window, with the alpha.c
file ready for editing, as shown in Figure 24-1.
Figure 24-1: Two source code files.
5. Click the alpha.c tab to begin editing that file.
6. Type the source code from Listing 24-2 into the alpha.c
file in Code::Blocks.
7. Save the ex2401 project.
8. Build and run.
Listing 24-2: The alpha.c Source Code File
#include <stdio.h>
void second(void)
{
puts("Glad to be here!");
}
Here’s the output I saw in the test window on my computer:
Second module, I send you greetings!
Glad to be here!
The two source code files aren't "glued together" by the compiler; each source code file is compiled individually. A separate object code file is created for each one: main.o
and alpha.o
. It's these two object code files that are then linked together, combined with the C standard library, to form the final program.
The main module for a multi-module C program is traditionally named
main.c
. That's probably why Code::Blocks names the first (and, often, only) project source code file main.c
.
Only source code files contained within the same project — found beneath the Sources branch, as shown in Figure 24-1 — are linked together.
To compile and link source code files in a terminal window, use the following command:
gcc main.c alpha.c -o ex2401
This command compiles the source code files main.c
and alpha.c
, links together their object files, and then creates as output (-o
) the program file ex2401
.
Sharing variables between modules
The best way to share a variable between several functions in a huge project is to make that variable global. (The specifics for that operation are found in Chapter 16.) The global variable needs to be declared in only one module, usually the main module. For the other modules to access that variable, they must employ the extern
keyword.
The extern
keyword doesn't declare a global variable. It merely tells the compiler that somewhere, in some other module, a global variable is to be found. That way, the compiler doesn't freak out. Here's the extern
keyword's format:
extern
type
name
type
is a variable type, the same type as the global variable being referenced. name
is the global variable's name. Getting both the type
and name
correct is what keeps the compiler happy.
Like a global variable, the extern
statement is generally found at the top of the source code, not within any specific function. Listings 24-3 and 24-4 provide examples.
Listing 24-3 shows the main module, with the second()
function prototyped at Line 4. The prototype is required because the second()
function is called at Line 11. You don't need to prototype all functions in another module, only those referenced or called.
Listing 24-3: Code for main.c and a Global Variable
#include <stdio.h>
#include <stdlib.h>
void second(void);
int count;
int main()
{
for(count=0;count<5;count++)
second();
return 0;
}
Global variable count
is declared at Line 6. It's used in the for
loop at Line 10, but it's also used in the second.c
source code file, shown in Listing 24-4.
Listing 24-4: Code for second.c Using the Global Variable
#include <stdio.h>
extern int count;
void second(void)
{
printf("%d\n",count+1);
}
The second.c
source code file is illustrated in Listing 24-4. It uses the global variable count
, which is declared in the main.c
file. To properly access that global variable, Line 3 in Listing 24-4 identifies the variable as an external int
. The count
variable is then used in the second()
function — specifically, at Line 7.
Exercise 24-2: Create a new project in Code::Blocks that incorporates both source code files shown in Listings 24-3 and 24-4. Build and run.
Creating a custom header file
As multi-module projects grow more complex, you find the first part of each source code file growing longer and longer: More prototypes, more constants, and more global variables and structures are required for each module. Rather than burden your code with redundancies, you can create a header file for the project.
A header file contains just about everything you can put into a source code file. Specifically, you should put items in the header file that would otherwise go into every source code module. Listing 24-5 shows a sample header file.
Listing 24-5: Header File ex2403.h
#include <stdio.h>
#include <stdlib.h>
/* prototypes */
void fillstructure(void);
void printstructure(void);
/* constants */
/* variables */
struct thing {
char name[32];
int age;
};
typedef struct thing human;
The header file shown in Listing 24-5 starts with some include
directives, which is fine; as long as those header files are required by each module in the program, you can specify them in your own header file. Some programmers choose to do so; others do not.
Two prototypes are specified at Lines 6 and 7. Again, one reason for having a header file is to prototype, especially across multiple modules.
The header file in Listing 24-5 lacks constants, though placing these items in a header file is quite common. I’ve added a comment at Line 9 in case the program grows constants later.
Finally, the structure thing
is defined at Line 13. Then Line 18 uses typedef
so that the word human (instead of struct thing
) can be used in the code. I'm not a fan of typedef
, although I stuck the code into Listing 24-5 as an example.
Other popular items to include in a header file are macros. These are preprocessor directives that can also help simplify your code. You can read about them at my blog:
www.c-for-dummies.com/blog/?page_id=2
To use a local header file in your code, you specify it on a line, just like any other header file. The big difference is that double quotes are used instead of angle brackets. For example:
#include "ex2403.h"
The compiler looks for the header filename in double quotes in the current directory, along with the source code file(s). If the file isn’t in that directory, you need to specify a pathname, as in
#include "headers/ex2403.h"
Listing 24-6 demonstrates how the header file in Listing 24-5 is used.
Listing 24-6: Project ex2403 main.c Source Code
#include "ex2403.h"
human person;
int main()
{
fillstructure();
printstructure();
return 0;
}
void fillstructure(void)
{
printf("Enter your name: ");
fgets(person.name,31,stdin);
printf("Enter your age: ");
scanf("%d",&person.age);
}
void printstructure(void)
{
printf("You are %s\n",person.name);
printf("And you are %d years old.\n",person.age);
}
Line 1 of the source code shown in Listing 24-6 includes the custom header file, ex2403.h
. The typedef human
is then used at Line 3. That's it! No other declarations are necessary in the source code because they've been handled by the custom header.
Exercise 24-3: Create a new project in Code::Blocks. Create a new header file, ex2403.h
, for the project, and copy the code from Listing 24-5 into that file. (Use the steps from the earlier section Linking two source code files to create a new file, naming it ex2403.h
and adding it to the current project.) Copy the source code from Listing 24-6 into the main.c
file. Build and run.
Exercise 24-4: Split out the fillstructure()
and printstructure()
functions from Listing 24-6 so that each appears in its own source code file, input.c
and output.c
, respectively. Build the multi-module program.
Other Libraries to Link
Throughout this book, your programs have linked in the standard C library. This process works fine for most purposes, such as the basic console applications in this book. When your programs require more sophistication, however, they need to use other libraries.
If you’re coding something graphical, you’ll want to link in a graphics library. Or if you’re doing fancy console (text) programming, you’ll want to link in the NCurses library. These libraries, and the functions they include, greatly augment the program’s capabilities.
The functions used in your code are the keys to determining which libraries to use. Just as a function’s man page documents the header files to include, you may also see a library listed.
For example, the printf()
function's man page has these two entries right up front:
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <stdio.h>
The first entry tells you that the function requires the standard C library, named libc
. The -lc
item shows the switch that's required if you're linking code in a terminal window. The next entry explains that the function requires the inclusion of the stdio.h
header file.
Regrettably, not every man page is as clear about which library is required. In some cases, you have to dig into the documentation to determine whether a library needs to be linked in. A linker error message is also a clue, though not a descriptive one.
Most compilers are configured to link in the standard C library. If another library needs to be linked in, it must be specified directly. Follow these steps in Code::Blocks:
1. Start a new project or save the current project.
2. Choose Project⇒Build Options.
The Project Build Options dialog box appears.
3. Click the Linker Settings tab.
The tab is found near the top-center part of the dialog box.
4. Click the Add button to bring in another library.
5. In the Add Library dialog box, click the Ellipsis (...) button to browse for a library.
Now comes the tough part: You need to locate where the compiler keeps the C language libraries. On a Unix system, the traditional directory is /usr/lib/
. On a Windows system, its location is relative to wherever the compiler is installed.
For example, on my PC, Code::Blocks installed the libraries in this folder:
C:\Program Files (x86)\CodeBlocks\MinGW\lib\
If you’re using a library you’ve just installed, you need to browse to its folder, assuming that the installation program didn’t place the library with the rest of them.
6. Browse to the folder containing the C libraries.
7. Choose the needed library.
For example, your code may use a math function that requires the libm
(math) library to be linked in. In that case, choose the libm.a
file from the list. (The filename extension may not be .a
on your computer, but the filename will be libm
.)
8. Click the Open button.
9. If you’re prompted to keep the library link as a relative path, click the No button.
I prefer absolute paths to library files. If you move the project to another folder in the future, you’ll thank me.
10. Click the OK button in the Add Library dialog box.
The library is now listed in the Link Libraries area of the window.
11. Click the OK button to return to your project.
At this point, building the project includes the new library automatically. If you have a keen eye, you can see the library linked in on the build log, found at the bottom of the Code::Blocks window.
The variety and purpose of the various libraries available to a C compiler depend on what you plan to do. Generally speaking, library packages can be found and downloaded from the Internet or obtained from other sources. For example, a hardware manufacturer may provide a library you can use to program its specific device.
Adding one or two libraries to your source code makes the resulting program grow larger. That’s okay: If you need the library’s functions, your program gets bulkier as a result.
Back in the old days, the standard C library came in various sizes, some designed to keep code tiny because of limited memory on most computers.