📄 Page
1
(This page has no text content)
📄 Page
2
MEAP Edition Manning Early Access Program Modern C Third Edition Revised for C 23 Version 4 2023 Jens Gustedt has released the manuscript of this work under a Creative Commons license for non-commercial use (CC BY NC). Jens Gustedt has granted to Manning Publications the exclusive commercial right to publish this work in print and electronic formats throughout the world. For more information on this and other Manning titles go to manning.com
📄 Page
3
About the Third edition Modern C was originally published as "Modern C" on Feb 13, 2018. Manning published the revised edition under the name “Modern C, First Edition” on Dec 2, 2019. With this new version, we are reconciling the edition numbers as "Modern C, Third Edition"
📄 Page
4
Acknowledgments Special thanks go to the people that encouraged the writing of this book by providing me with constructive feedback, including colleagues and other interested readers, Cédric Bastoul, LucasNussbaum, Vincent Loech- ner, Kliment Yanev, Szabolcs Nagy, Marcin Kowalczuk, Ali Asad Lotia, Richard Palme, Yann Barsamian, Fernando Oleo, Róbert Kohányi, Jean-Michel Gorius, Martin Uecker ... Manning’s staff Jennifer Stout, Nitin Gode and Tiffany Taylor, Frances Buontempo, ... ... and the impressive number of reviewers provided by Manning for both editions that they managed. Many others have contributed to the success of this book, my sincerest thanks to all of you.
📄 Page
5
About this book TheC programming language has been around since the early seventies (see Ritchie [1993]). Since then, C has been used in an incredible number of applications. Programs and sys- tems written in C are all around us: in personal computers, phones, cameras, set-top boxes, refrigerators, cars, mainframes, satellites ... basically in any modern device that has a pro- grammable interface. In contrast to the ubiquitous presence of C programs and systems, good knowledge of and about C is much more scarce. Even experienced C programmers often appear to be stuck in some degree of self-inflicted ignorance about the modern evolution of the C language. A likely reason for this is that C is seen as an "easy to learn" language, allowing a programmer with little experience to quickly write or copy snippets of code that at least appear to do what it’s supposed to. In a way, C fails to motivate its users to climb to higher levels of knowledge. This book is intended to change that general attitude, so it is organized in levels that reflect familiarity with the C language and programming in general. This structure may go against some habits of the book’s readers; in particular, it splits some difficult subjects (such as pointers) across levels in order to not swamp readers too early with the wrong information. We’ll explain the book’s organization in more detail shortly. Generally, althoughmany universally applicable ideas will be presented, that would also be valid for other programming languages (such as Java, Python, Ruby, C# or C++) the book primarily addresses concepts and practices that are unique to C or are of particular value when programming in the C language.
📄 Page
6
C revisions As the title of this book suggests, today’s C is not the same language as the one originally designed by its creator. Right from the start, C has been in a continuous process of adjust- ment and improvement. Usually, early C is referred to as K&R C (Kernighan and Ritchie C) after the first book thatmade the language popularKernighan andRitchie [1978]. Since then, it has undergone an important standardization and extension process, now driven by ISO, the International Standards Organization. This led to the publication of a series of C standards in 1989, 1999, 2011, 2018 and 2024, commonly referred to as C89, C99, C11, C17 and C23. The C standards committee puts a lot of effort into guaranteeing backward compatibility such that code written for earlier revisions of the language, say C11, should compile to a semantically equivalent executable with a compiler that imple- ments a newer revision. Unfortunately, this backward compatibility has had the unwanted side effect of not motivating projects that could benefit greatly from the new features to update their code base. To emphasize on this progress of revisions, we indicate for newer features which standard revision introduced them. This edition This edition presents a considerable rework in view of the latest revision, C23, of the C standard. A lot of new material has been added and many expositions have been straight- ened out to reflect the new capabilities of the C programming language. So, in this book we will mainly refer to C23, as defined in C23, but at the time of this writing compilers don’t yet implement this standard completely. If you want to compile the examples in this book, you will need at least a compiler that implements most of C17. For the novelties that C23 introduces we provide a compatibility header and discuss how to possibly generate a suitable C compiler and C library platform on POSIX systems as a fallback in annex 4. Beware, that this is not meant as a permanent tool, but only a crutch while platforms adapt. C and C++ Programming has become a very important cultural and economic activity, and C remains an important element in the programming world. As in all human activities, progress in C is driven by many factors: corporate or individual interest, politics, beauty, logic, luck, ignorance, selfishness, ego, sectarianism, ... (add your primary motivation here). Thus the development of C has not been and cannot be ideal. It has flaws and artifacts that can only be understood with their historical and societal context. An important part of the context in which C developed was the early appearance of its sister language, C++. One common misconception is that C++ evolved from C by adding its particular features. Although this is historically correct (C++ evolved from a very early C), it is not particularly relevant today. In fact, C and C++ separated from a common ancestor more than 30 years ago and have evolved separately ever since. But this evolution of the two languages has not taken place in isolation; they have exchanged and adopted each other’s concepts over the years. Some new features, such as the addition of atomics
📄 Page
7
and threads, have been designed in close collaboration between the C and C++ standard committees. Nevertheless, many differences remain, and generally all that is said in this book is about C, not C++. Many code examples that are given will not even compile with a C++ compiler. So we should not mix sources of both languages. Takeaway #1 C and C++ are different: don’t mix them, and don’t mix them up. Note that when you are working through this book, you will encounter many lines marked like that one. These are takeaways that summarize features, rules, recommendations, and so on. There is a list of these takeaways toward the end of the book, which you might use as a cheat sheet. Requirements To be able to profit from this book, you need to fulfill some minimal requirements. If you are uncertain about any of these, please obtain or learn them first; otherwise, you might waste a lot of time. First, you can’t learn a programming language without practicing it, so you must have a decent programming environment at your disposal (usually on a PC or laptop), and you mustmaster it to some extent. This environment can be integrated (an IDE) or a collection of separate utilities. Platforms vary widely in what they offer, so it is difficult to advise on specifics. On Unix-like environments such as Linux and Apple’s macOS, you will find editors such as emacs and vim, and compilers such as c99, c17 gcc, and clang. You must be able to do the following: 1 Navigate your file system. File systems on computers are usually organized hierarchi- cally in directories. You must be able to navigate through these to find and manipulate files. 2 Edit programming text. This is different from editing a letter in a word processing environment. Your environment, editor, or whatever it is called should have a basic understanding of the programming language C. You will see that if you open a C file (which usually has the file extension .c). It might highlight some keywords or help you indent your code according to the nestedness of {} brackets. 3 Execute a program. The programs you will see here are very basic at first and will not offer you any graphical features. They need to be launched in the command line. An example of such a program that is launched that way is the compiler. On Unix-like environments, the command line is usually called a shell and is launched in a (or the) console or terminal. 4 Compile programming text. Some environments provide a menu button or a key- board shortcut for compilation. An alternative to that is to launch the compiler in the
📄 Page
8
command line of a terminal. This compiler must adhere to recent standards; don’t waste your time with a compiler that does not conform. If you have never programmed before, this book will be tough. Knowing some of the following will help: Basic, C (historical revisions), C++, Fortran, R, bash, JavaScript, Java, MATLAB, Perl, Python, Scilab, and so on. But perhaps you have had some other pro- gramming experience,maybe evenwithout noticing.Many technical specifications actually come in some sort of specialized language that can be helpful as an analogy: for example, HTML for web pages and LaTeX for document formatting. You should have an idea of the following concepts, although their precise meanings may be a bit different in C than in the context where you learned them: 1 Variables—Named entities that hold values 2 Conditionals—Doing something (or not) subject to a precise condition 3 Iteration — Doing something repeatedly for a specified number of times or until a certain condition is met Source code Many of the programming code snippets that are presented in this book are publicly avail- able, see https://inria.hal.science/hal-03345464/document. This allows you to view them in context and to compile them and try them out. The archive also con- tains a Makefile with a description of the components that are needed to compile these files. It is centered around Linux or, more generally, POSIX systems, but it may also help you to find out what you need when you are on a different system. Exercises and challenges Throughout this book, you’ll see exercises that are meant to get you thinking about the concepts being discussed. These are probably best done directly along with your reading. Then there is another category called “challenges.” These are generally more demanding. You will need to do some research to even understand what they are about, and the solu- tions will not come all by themselves: they will require effort. They will take more time, sometimes hours or, depending on your degree of satisfaction with your work, even days. The subjects covered in these challenges are the fruit of my own personal bias toward “in- teresting questions” from my personal experience. If you have other problems or projects in your studies or your work that cover the same ground, they should do equally well. The important aspect is to train yourself by first searching for help and ideas elsewhere, and then to get your hands dirty and get things done. You will only learn to swim if you jump into the water. Organization This book is organized in levels, numbered from 0 to 3. The starting level 0, named "En- counter," will summarize the very basics of programming with C. Its principal role is to remind you of the main concepts we have mentioned and familiarize you with the spe-
📄 Page
9
cial vocabulary and viewpoints that C applies.1 By the end of it, even if you don’t have much experience in programming with C, you should be able to understand the structure of simple C programs and start writing your own. The "Acquaintance" level 1 details most principal concepts and features such as control structures, data types, operators, and functions. It should give you a deeper understanding of the things that are going on when you run your programs. This knowledge should be sufficient for an introductory course in algorithms and other work at that level, with the notable caveat that pointers are not yet fully introduced. The "Cognition" level 2 goes to the heart of the C language. It fully explains pointers, familiarizes you with C’s memory model, and allows you to understand most of C’s li- brary interface. Completing this level should enable you to write C code professionally; it therefore begins with an essential discussion about the writing and organization of C programs. I personally would expect anybody who graduated from an engineering school with a major related to computer science or programming in C to master this level. Don’t be satisfied with less. The "Experience" level 3 then goes into detail about specific topics, such as performance, reentrancy, atomicity, threads, and type-generic programming. These are probably best discovered as you go, which is when you encounter them in the real world. Nevertheless, as a whole, they are necessary to round off the discussion and to provide you with full expertise in C. Anybody with some years of professional programming in C or who heads a software project that uses C as its main programming language should master this level. Author Jens Gustedt completed his studies of mathematics at the Univer- sity of Bonn and Berlin Technical University. His research at that time covered the intersection between discrete mathematics and ef- ficient computation. Since 1998, he has been working as a senior scientist at the French National Institute for Computer Science and Control (INRIA), first in the LORIA lab, Nancy, and since 2013 in the ICube lab, Strasbourg, where he is a deputy director since 2023. Throughout his career, most of his scientific research has been accompanied by the development of software, at the beginning mostly in C++, and then later exclusively in C. He serves for AFNOR (the French standards organization) as an expert on the ISO committee JTC1/SC22/WG14 and was co-editor for the C standard document C17 and for the ini- tial phase of C23. He also has a successful blog that deals with programming in C and related topics: https://gustedt.wordpress.com. 1One of C’s special viewpoints is that indexing starts at 0, and not at 1 as in Fortran.
📄 Page
10
About the cover illustration The figure on the cover of Modern C is captioned “Femme Dalmate” or woman from Dal- matia. The illustration is taken from a collection of dress costumes from various countries by Jacques Grasset de Saint Sauveur (1757-1810), titled “Costumes de Différents Pays”, pub- lished in France in the late 18th century. Each illustration is finely drawn and colored by hand. The rich variety of Grasset de Saint Sauveur’s collection reminds us vividly of how culturally apart the world’s towns and regions were just 250 years ago. Isolated from each other, people spoke different dialects and languages. In the streets or in the countryside, it was easy to identify where they lived and what their trade or station in life was just by their dress. The way we dress has changed since then and the diversity by region, so rich at the time, has faded away. It is now hard to tell apart the inhabitants of different continents, let alone different towns, regions, or countries. Perhaps we have traded cultural diversity for a more varied personal life—certainly for a more varied and fast-paced technological life. At a time when it is hard to tell one computer book from another, Manning celebrates the inventiveness and initiative of the computer business with book covers rich diversity of regional life of more than two centuries ago, brought back to life by Grasset de Saint Sauveur’s pictures.
📄 Page
11
welcome Thank you for purchasing the MEAP edition of Modern C, Third Edition. After over 40 years of development, C is still among the major programming languages, ubiquitously used in basically all modern electronic devices, ranging from a small music chip in a birthday greeting card, your refrigerator, your phone, your laptop, to mainframes or satellites. This book is meant to provide you with a leveled approach in learning and mastering C. The previous edition already has been largely successful and is considered by some as one of the reference books on the subject. This new edition has been the occasion to overhaul the presentation in many places, but its main purpose is the update to the new C standard, C23. The goal is to publish this new edition of Modern C at the same time as the new C standard goes through the procedure of ISO publication and as new releases of major compilers will implement all the new features that it brings. Among the most noticeable changes and additions that we handle are those for integers: there are new bit-precise types coined _BitInt(N), new C library headers <stdckdint.h> (for arithmetic with overflow check) and <stdbit.h> (for bit manipulation), possibilities for 128 bit types on modern architectures, and substantial improvements for enumeration types. Other new concepts in C23 include a nullptr constant and its underlying type, syntactic annotation with attributes, more tools for type generic programming such as type inference with auto and typeof, default initialization with {}, even for variable length arrays. and constexpr for name constants of any type. Furthermore, new material has been added, discussing compound expressions and lambdas, so-called “internationalization”, a comprehensive approach for program failure. During MEAP we will also add an appendix and a temporary include header for an easy transition to C23 on existing platforms, that will allow you to start off with C23 right away. We also encourage you to post any questions or comments you have about the content in the liveBook Discussion forum. We appreciate knowing where we can make improvements and increase your understanding of the material —Jens Gustedt
📄 Page
12
brief contents LEVEL 0: ENCOUNTER 1 Getting started 2 The principle structure of a program LEVEL 1: ACQUAINTANCE 3 Everything is about control 4 Expressing computations 5 Basic values and data 6 Derived data types 7 Functions 8 C library functions LEVEL 2: COGNITION 9 Style 10 Organization and documentation 11 Pointers 12 The C memory model 13 Storage 14 More involved processing and IO 15 Program failure LEVEL 3: EXPERIENCE 16 Performance
📄 Page
13
17 Function-like macros 18 Type-generic programming 19 Variations in control flow 20 Threads 21 Atomic access and memory consistency APPENDIXES Technical Annex Appendix A. Transitional code Appendix B. C Compilers Appendix C. C Libraries
📄 Page
14
Level 0 Encounter Our mascot for this level is the magpie, one of the most intelligent nonhuman species on earth. They are capable of elaborate social rituals and usage of tools. This first level of the book may be your first encounter with the programming language C. It provides you with a rough knowledge about C programs, their purpose, their struc- ture, and how to use them. It is not meant to give you a complete overview, it can’t and it doesn’t even try. On the contrary, it is supposed to give you a general idea of what this is all about, open up questions, and promote ideas and concepts. These then will be explained in detail in the higher levels.
📄 Page
15
1Getting started This section covers Introduction to imperative programming Compiling and running code In this section, I will introduce you to one simple program that has been chosen because it contains many of the constructs of the C language. If you already have programming experience, you may find that parts of it feel like needless repetition. If you lack such experience, you might feel overwhelmed by the stream of new terms and concepts. In either case, be patient. For those of you with programming experience, it’s very possible that there are subtle details you’re not aware of, or assumptions you have made about the language that are not valid, even if you have programmed C before. For those approaching programming for the first time, be assured that after approximately 10 pages your understanding will have increased a lot, and you should have a much clearer idea of what programming represents. An important bit of wisdom for programming in general, and for this book in particular, is summarized in the following citation from theHitchhiker’s Guide to the Galaxy byDouglas Adams Adams [1986]:
📄 Page
16
Takeaway 1 #1 Don’t panic. It’s not worth it. There are many cross references, links, and bits of side information in the text, and there is an index at the end. Follow those if you have a question. Or just take a break. Programming in C is about having the computer complete some specific tasks. A C pro- gram does that by giving orders, much as we would express such orders in the imperative tense in many human languages; thus the term imperative programming for this particular way of organizing computer programs. To get started and see what we are talking about, consider our first program in listing 1.0.1, which corresponds to the getting-started.c source file in the source directory. Listing 1.0.1 A first example of a C program 1 /* This may look like nonsense, but really is -*- mode: C -*- */ 2 #include <stdlib.h> 3 #include <stdio.h> 4 5 /* The main thing that this program does. */ 6 int main(int argc, [[maybe_unused]] char* argv[argc+1]) { 7 // Declarations 8 double A[5] = { 9 [0] = 9.0, 10 [1] = 2.9, 11 [4] = 3.E+25, 12 [3] = .00007, 13 }; 14 15 // Doing some work 16 for (size_t i = 0; i < 5; ++i) { 17 printf("element %zu is %g, \tits square is %g\n", 18 i, 19 A[i], 20 A[i]*A[i]); 21 } 22 23 return EXIT_SUCCESS; 24 } 1.1 Imperative programming You probably see that this is a sort of language, containing some weird words like main, include, for, and so on, which are laid out and colored in a peculiar way and mixed with a lot of strange characters, numbers, and text (“Doing some work”) that looks like ordi-
📄 Page
17
nary English. It is designed to provide a link between us, the human programmers, and a machine, the computer, to tell it what to do: to give it “orders.” Takeaway 1.1 #1 C is an imperative programming language. In this book, we will not only encounter the C programming language, but also some vocabulary from an English dialect, C jargon, the language that helps us to talk about C. It will not be possible to immediately explain each term the first time it occurs. But I will explain each one in time, and all of them are indexed so you can easily cheat and jumpC to more explanatory text, at your own risk.1 As you can probably guess from this first example, such a C program has different components that form some intermixed layers. Let’s try to understand it from the inside out. The visible result of running this program is to output 5 lines of text on the command terminal of your computer. On my computer, using this program looks something like this: Terminal 0 > ./getting-started 1 element 0 is 9, its square is 81 2 element 1 is 2.9, its square is 8.41 3 element 2 is 0, its square is 0 4 element 3 is 7e-05, its square is 4.9e-09 5 element 4 is 3e+25, its square is 9e+50 We can easily identify within our program the parts of the text that this program out- puts (printsC , in C jargon): the part of line 17 between quotes. The real action happens between that line and line 20. C calls this a statementC , which is a bit of a misnomer. Other languages would use the term instruction which describes the purpose better. This particular statement is a callC to a functionC named printf: getting-started.c 17 printf("element %zu is %g, \tits square is %g\n", 18 i, 19 A[i], 20 A[i]*A[i]); Here, the printf function receives four argumentsC , enclosed in a pair of parenthesesC , ( ... ): The funny-looking text (between the quotes) is a so-called string literalC that serves as a formatC for the output. Within the text are three markers (format specifiersC ) 1Such special terms from C jargon are marked with a C, as shown here.
📄 Page
18
that indicate the positions in the output where numbers are to be inserted. These markers start with a% character. This format also contains some special escape charactersC that start with a backslash: \t and \n. After a comma character, we find the word i. The thing i stands for will be printed in place of the first format specifier, %zu. Another comma separates the next argument A[i]. The thing this stands for will be printed in place of the second format specifier, the first %g. Last, again separated by a comma, appears A[i]*A[i], corresponding to the last %g. We will later explain what all of these arguments mean. Just remember that we identified the main purpose of the program (to print some lines on the terminal) and that it “orders” the printf function to fulfill that purpose. The rest is some sugarC to specify which numbers will be printed, and how many of them. 1.2 Compiling and running As shown in the previous subsection, the program text expresses what we want our com- puter to do. As such, it is just another piece of text that we have written and stored some- where on our hard disk, but the program text as such cannot be understood by your com- puter. There is a special program, called a compiler, that translates the C text into something that your machine can understand: the binary codeC or executableC . What that translated program looks like and how this translation is done are much too complicated to explain at this stage.2 Even this entire book will not be able to explain most of it; that would be the subject of another whole book. However, for the moment, we don’t need to understand more deeply, as we have the tool that does all the work for us. Takeaway 1.2 #1 C is a compiled programming language. The name of the compiler and its command-line arguments depend a lot on the platformC on which you will be running your program. There is a simple reason for this: the target binary code is platform dependentC : that is, its form and details depend on the computer on which you want to run it. A PC has different needs than a phone, and your refrigerator doesn’t speak the same “language” as your set-top box. In fact, that’s one of the reasons for C to exist: C provides a level of abstraction for all the different machine-specific languages (usually referred to as assemblerC ). 2In fact, the translation itself is done in several steps that go from textual replacement, over proper compi- lation, to linking. Nevertheless, the tool that bundles all this is traditionally called a compiler and not a translator, which would be more accurate.
📄 Page
19
Takeaway 1.2 #2 A correct C program is portable between different platforms. In this book, we will put a lot of effort into showing you how to write “correct” C programs that ensure portability. Unfortunately, there are some platforms that claim to be “C” but do not conform to the latest standards; and there are conforming platforms that accept incorrect programs or provide extensions to the C standard that are not widely portable. So, running and testing a program on a single platform will not always guarantee portability. It is the job of the compiler to ensure that the little program shown earlier, once trans- lated for the appropriate platform, will run correctly on your PC, your phone, your set-top box, and maybe even your refrigerator. That said, if you have a POSIX system (such as Linux ormacOS), there is a good chance that programs named c99 or c17might be present and that it is in fact a C compiler. You could try to compile the example program using the following command: Terminal 0 > c17 -Wall -o getting-started getting-started.c -lm The compiler should do its job without complaining and output an executable file called getting-started in your current directory.[Exs 3] In the example line, c17 is the compiler program. -Wall tells it to warn us about anything that it finds unusual. -o getting-started tells it to store the compiler outputC in a file named getting-started. getting-started.c names the source fileC , the file that contains the C code we have written. Note that the .c extension at the end of the filename refers to the C programming language. -lm tells it to add some standard numerical functions if necessary; we will need those later on. Now we can executeC our newly created executableC . Type in Terminal 0 > ./getting-started and you should see exactly the same output as I showed you earlier. That’s what portable means: wherever you run that program, its behaviorC should be the same. If you are not lucky and the compilation command didn’t work, you will have to look up the name of your compilerC in your system documentation. You might even have to [Exs 3]Try the compilation command in your terminal.
📄 Page
20
install a compiler if one is not available. 4The names of compilers vary. Here are some common alternatives that might do the trick: Terminal 0 > clang -std=c2x -Wall -lm -o getting-started getting-started.c 1 > gcc -std=c2x -Wall -lm -o getting-started getting-started.c 2 > icc -std=c2x -Wall -lm -o getting-started getting-started.c Here the option -std=c2x names the standard version “C2x” which was meant for C23 before we actually knew that it would be finished in 2023. Some of these compilers, even if they are present on your computer, might not compile the program without complaining.[Exs 5] With the program in listing 1.0.1, we presented an ideal world: a program that works and produces the same result on all platforms. Unfortunately, when programming yourself, very often you will have a program that works only partially and that may produce wrong or unreliable results. Therefore, let us look at the program in listing 1.2.1. It looks quite similar to the previous one. Listing 1.2.1 An example of a C program with flaws 1 /* This may look like nonsense, but really is -*- mode: C -*- */ 2 3 /* The main thing that this program does. */ 4 void main() { 5 // Declarations 6 int i; 7 double A[5] = { 8 9.0, 9 2.9, 10 3.E+25, 11 .00007, 12 }; 13 14 // Doing some work 15 for (i = 0; i < 5; ++i) { 16 printf("element %d is %g, \tits square is %g\n", 17 i, 18 A[i], 19 A[i]*A[i]); 20 } 21 4This is necessary in particular if you have a system with a Microsoft operating system. Microsoft’s native compilers are now catching up with C17, but I don’t know about their plans for C23. Many features that we discuss in this book might not work. For a discussion on alternative development environments, there, Chris Wellons’ blog entry “Four Ways to Compile C for Windows” (https://nullprogram.com/blog/2016/ 06/13/) might still be of interest. [Exs 5]Start writing a text report about your tests with this book. Note down which command worked for you.