Program Organization (with Examples in C)
Introduction In my book Why Learn C , Chapter 13, Program Organization , I wrote in part: For all but the most trivial programs, a typical C program is composed of several source ( .c ) files and header ( .h ) files. Often, .c and .h files come in pairs where the .c implements some functionality and the .h provides the “public” API for using it. All the functions comprising a program are spread…
Program Organization in Tidy, a Mid-Sized C Program
Introduction
In my book Why Learn C, Chapter 13, Program Organization, I discussed how most C programs consist of multiple source (.c) and header (.h) files. Typically, each .c file implements a specific functionality, while the corresponding .h file provides a public API for using that functionality. These pairs of files often work together to form a module or specialized aspect of the program. For example, a color.c file contains functions for printing text in color to a terminal, while color.h contains their declarations.
Program Structure in Tidy
Tidy, a mid-sized C program, demonstrates how to organize source files in a more complex project. Compared to the smaller ad program, Tidy is approximately three times larger. Here are some of its source files:
- array.c
- file_ext.c
- path_util.c
- symbol.h
- array.h
- file_ext.h
- path_util.h
- toml_lite.c
- bit_util.c
- fnv1a.c
- path_util_test.c
- toml_lite.h
- bit_util.h
- fnv1a.h
- pjl_config.h
- toml_test.c
- clang_util.c
- hash_table.c
- print.c
- trans_unit.c
- cli_options.c
- proxies.c
- type_traits.h
- cli_options.h
- include-tidy.c
- proxies.h
- typedef.c
- color.h
- include-tidy.h
- red_black.c
- typedef.h
- color.h
- include.c
- red_black.h
- unit_test.c
- config.h
- include.h
- red_black_test.c
- unit_test.h
- config_file.c
- ipath.c
- strbuf.c
- util.c
- config_file.h
- ipath.h
- strbuf.h
- util.h
- cxx.c
- options.c
- strbuf_test.c
- cxx.h
- symbol.c
Components of Tidy
Tidy can be broken down into several types of components:
1. Program-specific data structures and algorithms: Tidy includes a data structure to represent symbols referenced in a program, defined in symbol.h with implementations in symbol.c. This C++-specific code was later moved to cxx.c for better organization.
2. Generic data structures and algorithms: Tidy utilizes dynamic arrays, hash tables, red-black trees, and string buffers, which are necessary in C programs as they don't exist in the C standard library.
3. Program options: These allow the behavior of Tidy to be customized, such as comment styles, alignment columns, and colored output.
4. Command-line parsing: Tidy uses command-line options to set program options, often in a 1:1 correspondence with the program options.
5. Configuration file parsing: Tidy can also parse configuration files to set program options, which can be cumbersome to set from the command line.
6. Program-specific utilities: Functions that aren't entirely generic but are used in multiple places or improve the use of third-party libraries, like functions for dealing with Libclang in Tidy.
7. Generic utilities: Macros, error-handling functions, string-handling functions, and others that are useful across various parts of the program.
8. Test code: Tidy includes a small unit-test framework, test executables, and a functional-test framework.
Conclusion
Organizing source files effectively is crucial for maintaining and understanding larger programs. By separating program-specific and generic components, maximizing the reuse of generic components, and keeping program-specific code manageable, developers can create cleaner, more maintainable codebases. Tidy serves as an example of how to apply these principles in a mid-sized C program.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.