You picked up this book to move your programming skills one step forward. That is good, because you’ll definitely benefit from the hands-on knowledge provided in this book. If you have a lot of experience programming in C, you’ll learn the details of good design decisions and about their benefits and drawbacks. If you are fairly new to C programming, you’ll find guidance about design decisions, and you’ll see how these decisions are applied bit by bit to running code examples for building larger scale programs.
The book answers questions such as how to structure a C program, how to cope with error handling, or how to design flexible interfaces. As you learn more about C programming, questions often pop up, such as the following:
Should I return any error information I have?
Should I use the global variable errno
to do that?
Should I have few functions with many parameters or the other way around?
How do I build a flexible interface?
How can I build basic things like an iterator?
For object-oriented languages, most of these questions are answered to a great extent by the Gang of Four book Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Prentice Hall, 1997). Design patterns provide a programmer with best practices on how objects should interact and which object owns which other kinds of objects. Also, design patterns show how such objects can be grouped together.
However, for procedural programming languages like C, most of these design patterns cannot be implemented in the way described by the Gang of Four. There are no native object-oriented mechanisms in C. It is possible to emulate inheritance or polymorphism in the C programming language, but that might not be the first choice, because such emulation makes things unfamiliar for programmers who are used to programming C and are not used to programming with object-oriented languages like C++ and using concepts like inheritance and polymorphism. Such programmers may want to stick to their native C programming style that they are used to. However, with the native C programming style, not all object-oriented design patterns guidance is usable, or at least the specific implementation of the idea presented in a design pattern is not provided for non-object-oriented programming languages.
And that is where we stand: we want to program in C, but we cannot directly use most of the knowledge documented in design patterns. This book shows how to bridge this gap and implement hands-on design knowledge for the C programming language.
Let me tell you why the knowledge gathered in this book turned out to be very important for me and why such knowledge is hard to find.
In school I learned C programming as my first programming language. Just like every new C programmer, I wondered why arrays start with index 0, and I first rather randomly tried out how to place the operators *
and &
in order to finally get the C pointer magic working.
At university I learned how C syntax actually works and how it translates to bits and bytes on the hardware. With that knowledge I was able to write small programs that worked very well. However, I still had trouble understanding why longer code looked the way it did, and I certainly wouldn’t have come up with solutions like the following:
typedef
struct
INTERNAL_DRIVER_STRUCT
*
DRIVER_HANDLE
;
typedef
void
(
*
DriverSend_FP
)(
char
byte
);
typedef
char
(
*
DriverReceive_FP
)();
typedef
void
(
*
DriverIOCTL_FP
)(
int
ioctl
,
void
*
context
);
struct
DriverFunctions
{
DriverSend_FP
fpSend
;
DriverReceive_FP
fpReceive
;
DriverIOCTL_FP
fpIOCTL
;
};
DRIVER_HANDLE
driverCreate
(
void
*
initArg
,
struct
DriverFunctions
f
);
void
driverDestroy
(
DRIVER_HANDLE
h
);
void
sendByte
(
DRIVER_HANDLE
h
,
char
byte
);
char
receiveByte
(
DRIVER_HANDLE
h
);
void
driverIOCTL
(
DRIVER_HANDLE
h
,
int
ioctl
,
void
*
context
);
Looking at code like that prompted many questions:
Why have function pointers in the struct
?
Why do the functions need that DRIVER_HANDLE
?
What is an IOCTL, and why would I not have separate functions instead?
Why have explicit create and destroy functions?
These questions came up as I began writing industrial applications. I regularly came across situations where I realized I did not have the C programming knowledge, for example, to decide how to implement an iterator or to decide how to cope with error handling in my functions. I realized that although I knew C syntax, I had no clue how to apply it. I tried to achieve something but just managed to do it in a clumsy way or not at all. What I needed were best practices on how to achieve specific tasks with the C programming language. For example, I needed to know things like the following:
How can I acquire and release resources in an easy way?
Is it a good idea to use goto
for error handling?
Should I design my interface to be flexible, or should I simply change it when the need arises?
Should I use an assert
statement, or should I return an error code?
How is an iterator implemented in C?
It was very interesting for me to realize that while my experienced work colleagues had many different answers for these questions, nobody could point me to anything that documented these design decisions and their benefits and drawbacks.
So next I turned to the internet, and yet again I was surprised: it was very hard to find sound answers to these questions even though the C programming language has been around for decades. I found out that while there is much literature on the C programming language basics and its syntax, there’s not much on advanced C programming topics or how to write beautiful C code that holds up to industrial applications.
And that is exactly where this book comes in. This book teaches you how to advance your programming skills from writing basic C programs to writing larger-scale C programs that consider error handling and that are flexible regarding certain future changes in requirements and design. This book uses the concept of design patterns to provide you bit by bit with design decisions and their benefits and drawbacks. These design patterns are applied to running code examples that teach you how code like the earlier example evolves and why it ends up looking the way it does.
The presented patterns can be applied to any C programming domains. As I come from the domain of embedded programming in a multithreaded real-time environment, some of the patterns are biased towards that domain. Anyways, you’ll see that the general idea of the patterns can be applied to other C programming domains and even beyond the scope of C programming.
The design guidance in this book is provided in the form of patterns. The idea of presenting knowledge and best practices in the form of patterns comes from the architect Christopher Alexander in The Timeless Way of Building (Oxford University Press, 1979). He uses small pieces of well-proven solutions to tackle a huge problem in his domain: how to design and construct cities. The approach of applying patterns was adopted by the software development domain, where pattern conferences like the conference on Pattern Languages of Programs (PLoP) are held to extend the body of knowledge of patterns. In particular, the book Design Patterns: Elements of Reusable Object-Oriented Software by the Gang of Four (Prentice Hall, 1997) had a significant impact and made the concept of design patterns well known to software developers.
But what exactly is a pattern? There are many definitions out there, and if you are deeply interested in the topic, then the book Pattern-Oriented Software Architecture: On Patterns and Pattern Languages by Frank Buschmann et al. (Wiley, 2007) can provide you with accurate descriptions and details. For the purposes of this book, a pattern provides a well-proven solution to a real-life problem. The patterns presented in this book have the structure shown in Table P-1.
Pattern section | Description |
---|---|
Name | This is the name of the pattern, which should be easy to remember. The aim is that this name will be used by programmers in their everyday language (as is the case with the Gang of Four patterns, where you hear programmers say, “And the Abstract Factory creates the object”). Pattern names are capitalized in this book. |
Context | The context section sets the scene for the pattern. It tells you under which circumstances this pattern can be applied. |
Problem | The problem section gives you information about the issue you want to tackle. It starts with the major problem statement written in bold font type and then adds details on why the problem is hard to solve. (In other pattern formats, these details go into a separate section called “forces.”) |
Solution | This section provides guidance on how to tackle the problem. It starts with stating the main idea of the solution written in bold font type and continues with details about the solution. It also provides a code example in order to give very concrete guidance. |
Consequences | This section lists the benefits and drawbacks of applying the described solution. When applying a pattern, you should always confirm that the consequences that arise are OK with you. |
Known uses | The known uses give you evidence that the proposed solution is good and actually works in real-life applications. They also show you concrete examples to help you understand how to apply the pattern. |
A major benefit of presenting design guidance in the form of patterns is that these patterns can be applied one after another. If you have a huge design problem, it’s hard to find the one guidance document and the one solution that addresses exactly that problem. Instead, you can think of your huge and very specific problem as a sum of many smaller and more generic problems, and you can tackle these problems bit by bit by applying one pattern after the other. You simply check the problem descriptions of the patterns and apply the one that fits your problem and that has consequences you can live with. These consequences might lead to another problem that you can then address by applying another pattern. That way you incrementally design your code instead of trying to come up with a complete up-front design before even writing the first line of code.
You should already know C programming basics. You should know the C syntax and how it works—for example, this book won’t teach you what a pointer is or how to use it. This book delivers hints and guidance on advanced topics.
The chapters in this book are self-standing. You can read them in an arbitrary order, and you can simply pick out the topics you are interested in. You’ll find an overview of all patterns in the next section, and from there you can jump to the patterns you are interested in. So if you know exactly what you are looking for, you can start right there.
If you are not looking for one particular pattern, but instead want to get an overview of possible C design options, read through Part I of the book. Each chapter there focuses on a particular topic, starting with basic topics like error handling and memory managment, and then moving to more advanced and specific topics like interface design or platform-independent code. The chapters each present patterns related to that topic and a running code example that shows bit by bit how the patterns can be applied.
Part II of this book shows two larger running examples that apply many of the patterns from Part I. Here you can learn how to build up some larger piece of software bit by bit through the application of patterns.
You’ll find an overview of all patterns presented in this book in Tables P-2 through P-10. The tables show a short form of the patterns that only contains a brief description of the core problem, followed by the keyword “Therefore,” followed by the core solution.
The following typographical conventions are used in this book:
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Used to highlight the problem and solution for each pattern.
Constant width
Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords.
This element signifies a general note.
This element indicates a warning or caution.
The code examples in this book show short code snippets which focus on the core idea to showcase the patterns and their application. The code snippets by themselves won’t compile, because to keep it simple several things are omitted (for example, include files). If you are interested in getting the full code which does compile, you can download it from GitHub at https://github.com/christopher-preschern/fluent-c.
If you have a technical question or a problem using the code examples, please send email to [email protected].
This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission.
We appreciate, but generally do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Fluent C by Christopher Preschern (O’Reilly). Copyright 2023 Christopher Preschern, 978-1-492-09733-4.”
If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at [email protected].
The patterns in this book all present existing code examples which apply these patterns. The following list shows the references to these code examples:
B&R Automation Runtime operating system (proprietary and undisclosed code of the company B&R Industrial Automation GmbH)
B&R Visual Components automation system visualization editor (proprietary and undisclosed code of the company B&R Industrial Automation GmbH)
Netdata real-time performance monitoring and visualization system
For more than 40 years, O’Reilly Media has provided technology and business training, knowledge, and insight to help companies succeed.
Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit https://oreilly.com.
Please address comments and questions concerning this book to the publisher:
We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at https://oreil.ly/fluent-c.
Email [email protected] to comment or ask technical questions about this book.
For news and information about our books and courses, visit https://oreilly.com.
Find us on LinkedIn: https://linkedin.com/company/oreilly-media
Follow us on Twitter: https://twitter.com/oreillymedia
Watch us on YouTube: https://www.youtube.com/oreillymedia
I want to thank my wife Silke who by now even knows what patterns are :-) and I want to thank my daughter Ylvi. They both make my life happier, and they both make sure that I don’t end up sitting in front of my computer working all the time, but that I instead enjoy life.
This book would not have come to life without the help of many pattern enthusiasts. I want to thank all the participants of Writers’ Workshops at the European Conference on Pattern Languages of Programs for providing me with feedback on the patterns. In particular, I want to thank the following people, who provided me with very helpful feedback during the so-called shepherding process of that conference: Jari Rauhamäki, Tobias Rauter, Andrea Höller, James Coplien, Uwe Zdun, Thomas Raser, Eden Burton, Claudius Link, Valentino Vranić, and Sumit Kalra. Special thanks also to my work colleagues, in particular to Thomas Havlovec, who made sure that I got the C programming details in my patterns right. Robert Hanmer, Michael Weiss, David Griffiths, and Thomas Krug spent a lot of time for reviewing this book and provided me with additional ideas how to improve it—thank you very much! Thanks also to the whole team at O’Reilly who helped me a lot in making this book happen. In particular, I want to thank my development editor, Corbin Collins, and my production editor, Jonathon Owen.
The content of this book is based on the following papers that were accepted at the European Conference on Pattern Languages of Programs and published with ACM. These papers can be accessed for free at the website http://www.preschern.com.
“A Pattern Story About C Programming,” EuroPLoP ’21: 26th European Conference on Pattern Languages of Programs, July 2015, article no. 53, 1–10, https://dl.acm.org/doi/10.1145/3489449.3489978.
“Patterns for Organizing Files in Modular C Programs,” EuroPLoP ’20: Proceedings of the European Conference on Pattern Languages of Programs, July 2020, article no. 1, 1–15, https://dl.acm.org/doi/10.1145/3424771.3424772.
“Patterns to Escape the #ifdef Hell,” EuroPLop ’19: Proceedings of the 24th European Conference on Pattern Languages of Programs, July 2019, article no. 2, 1–12, https://dl.acm.org/doi/10.1145/3361149.3361151.
“Patterns for Returning Error Information in C,” EuroPLop ’19: Proceedings of the 24th European Conference on Pattern Languages of Programs, July 2019, article no. 3, 1–14, https://dl.acm.org/doi/10.1145/3361149.3361152.
“Patterns for Returning Data from C Functions,” EuroPLop ’19: Proceedings of the 24th European Conference on Pattern Languages of Programs, July 2019, article no. 37, 1–13, https://dl.acm.org/doi/10.1145/3361149.3361188.
“C Patterns on Data Lifetime and Ownership,” EuroPLop ’19: Proceedings of the 24th European Conference on Pattern Languages of Programs, July 2019, article no. 36, 1–13, https://dl.acm.org/doi/10.1145/3361149.3361187.
“Patterns for C Iterator Interfaces,” EuroPLoP ’17: Proceedings of the 22nd European Conference on Pattern Languages of Programs, July 2017, article no. 8, 1–14, https://dl.acm.org/doi/10.1145/3147704.3147714.
“API Patterns in C,” EuroPlop ’16: Proceedings of the 21st European Conference on Pattern Languages of Programs, July 2016, article no. 7, 1–11, https://dl.acm.org/doi/10.1145/3011784.3011791.
“Idioms for Error Handling in C,” EuroPLoP ’15: Proceedings of the 20th European Conference on Pattern Languages of Programs, July 2015, article no. 53, 1–10, https://dl.acm.org/doi/10.1145/2855321.2855377.
3.138.137.127