Something went wrong. Try again.
A Tour of C++ for experienced programmers, as if C++26 is the only version that ever existed.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343<!DOCTYPE HTML><html lang="en" class="light sidebar-visible" dir="ltr"> <head> <!-- Book generated using mdBook --> <meta charset="UTF-8"> <title>Fast is a specification - A Tour of C++26</title>
<!-- Custom HTML head -->
<meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon-de23e50b.svg"> <link rel="shortcut icon" href="favicon-8114d1fc.png"> <link rel="stylesheet" href="css/variables-8adf115d.css"> <link rel="stylesheet" href="css/general-e96d0476.css"> <link rel="stylesheet" href="css/chrome-d279d366.css"> <link rel="stylesheet" href="css/print-9e4910d8.css" media="print">
<!-- Fonts --> <link rel="stylesheet" href="fonts/fonts-9644e21d.css">
<!-- Highlight.js Stylesheets --> <link rel="stylesheet" id="mdbook-highlight-css" href="highlight-493f70e1.css"> <link rel="stylesheet" id="mdbook-tomorrow-night-css" href="tomorrow-night-4c0ae647.css"> <link rel="stylesheet" id="mdbook-ayu-highlight-css" href="ayu-highlight-3fdfc3ac.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript --> <script> const path_to_root = ""; const default_light_theme = "light"; const default_dark_theme = "navy"; window.path_to_searchindex_js = "searchindex-7c7963f3.js"; </script> <!-- Start loading toc.js asap --> <script src="toc-0eddcac6.js"></script> </head> <body> <div id="mdbook-help-container"> <div id="mdbook-help-popup"> <h2 class="mdbook-help-title">Keyboard shortcuts</h2> <div> <p>Press <kbd>←</kbd> or <kbd>→</kbd> to navigate between chapters</p> <p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p> <p>Press <kbd>?</kbd> to show this help</p> <p>Press <kbd>Esc</kbd> to hide this help</p> </div> </div> </div> <div id="mdbook-body-container"> <!-- Work around some values being stored in localStorage wrapped in quotes --> <script> try { let theme = localStorage.getItem('mdbook-theme'); let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); }
if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } </script>
<!-- Set the theme before any content is loaded, prevents flash --> <script> const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme; let theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = default_theme; } const html = document.documentElement; html.classList.remove('light') html.classList.add(theme); html.classList.add("js"); </script>
<input type="checkbox" id="mdbook-sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed --> <script> let sidebar = null; const sidebar_toggle = document.getElementById("mdbook-sidebar-toggle-anchor"); if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } else { sidebar = 'hidden'; sidebar_toggle.checked = false; } if (sidebar === 'visible') { sidebar_toggle.checked = true; } else { html.classList.remove('sidebar-visible'); } </script>
<nav id="mdbook-sidebar" class="sidebar" aria-label="Table of contents"> <!-- populated by js --> <mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox> <noscript> <iframe class="sidebar-iframe-outer" src="toc.html"></iframe> </noscript> <div id="mdbook-sidebar-resize-handle" class="sidebar-resize-handle"> <div class="sidebar-resize-indicator"></div> </div> </nav>
<div id="mdbook-page-wrapper" class="page-wrapper">
<div class="page"> <div id="mdbook-menu-bar-hover-placeholder"></div> <div id="mdbook-menu-bar" class="menu-bar sticky"> <div class="left-buttons"> <label id="mdbook-sidebar-toggle" class="icon-button" for="mdbook-sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="mdbook-sidebar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"/></svg></span> </label> <button id="mdbook-theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="mdbook-theme-list"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M371.3 367.1c27.3-3.9 51.9-19.4 67.2-42.9L600.2 74.1c12.6-19.5 9.4-45.3-7.6-61.2S549.7-4.4 531.1 9.6L294.4 187.2c-24 18-38.2 46.1-38.4 76.1L371.3 367.1zm-19.6 25.4l-116-104.4C175.9 290.3 128 339.6 128 400c0 3.9 .2 7.8 .6 11.6c1.8 17.5-10.2 36.4-27.8 36.4H96c-17.7 0-32 14.3-32 32s14.3 32 32 32H240c61.9 0 112-50.1 112-112c0-2.5-.1-5-.2-7.5z"/></svg></span> </button> <ul id="mdbook-theme-list" class="theme-popup" aria-label="Themes" role="menu"> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-default_theme">Auto</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-light">Light</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-rust">Rust</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-coal">Coal</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-navy">Navy</button></li> <li role="none"><button role="menuitem" class="theme" id="mdbook-theme-ayu">Ayu</button></li> </ul> <button id="mdbook-search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="mdbook-searchbar"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg></span> </button> </div>
<h1 class="menu-title">A Tour of C++26</h1>
<div class="right-buttons"> <a href="print.html" title="Print this book" aria-label="Print this book"> <span class=fa-svg id="print-button"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64v96h64V64H354.7L384 93.3V160h64V93.3c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0H128zM384 352v32 64H128V384 368 352H384zm64 32h32c17.7 0 32-14.3 32-32V256c0-35.3-28.7-64-64-64H64c-35.3 0-64 28.7-64 64v96c0 17.7 14.3 32 32 32H64v64c0 35.3 28.7 64 64 64H384c35.3 0 64-28.7 64-64V384zm-16-88c-13.3 0-24-10.7-24-24s10.7-24 24-24s24 10.7 24 24s-10.7 24-24 24z"/></svg></span> </a>
</div> </div>
<div id="mdbook-search-wrapper" class="hidden"> <form id="mdbook-searchbar-outer" class="searchbar-outer"> <div class="search-wrapper"> <input type="search" id="mdbook-searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="mdbook-searchresults-outer" aria-describedby="searchresults-header"> <div class="spinner-wrapper"> <span class=fa-svg id="fa-spin"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M304 48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zm0 416c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM48 304c26.5 0 48-21.5 48-48s-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48zm464-48c0-26.5-21.5-48-48-48s-48 21.5-48 48s21.5 48 48 48s48-21.5 48-48zM142.9 437c18.7-18.7 18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zm0-294.2c18.7-18.7 18.7-49.1 0-67.9S93.7 56.2 75 75s-18.7 49.1 0 67.9s49.1 18.7 67.9 0zM369.1 437c18.7 18.7 49.1 18.7 67.9 0s18.7-49.1 0-67.9s-49.1-18.7-67.9 0s-18.7 49.1 0 67.9z"/></svg></span> </div> </div> </form> <div id="mdbook-searchresults-outer" class="searchresults-outer hidden"> <div id="mdbook-searchresults-header" class="searchresults-header"></div> <ul id="mdbook-searchresults"> </ul> </div> </div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM --> <script> document.getElementById('mdbook-sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible'); document.getElementById('mdbook-sidebar').setAttribute('aria-hidden', sidebar !== 'visible'); Array.from(document.querySelectorAll('#mdbook-sidebar a')).forEach(function(link) { link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1); }); </script>
<div id="mdbook-content" class="content"> <main> <h1 id="fast-is-a-specification"><a class="header" href="#fast-is-a-specification">Fast is a specification</a></h1><h2 id="predict-measure-change"><a class="header" href="#predict-measure-change">Predict, measure, change</a></h2><p>A performance claim is a hypothesis until it is measured. The correct workflow is to predict the cost, measure it with a reliable tool, then change the code and re-measure. Only after the measurement can a claim be accepted as true.</p><p>Guessing about performance fails because modern compilers and CPUs are too clever. A statement that a piece of code is slow can be incorrect, and a statement that it is fast can be incorrect as well. The only reliable route is to turn the claim into a measurement, which is why this chapter gives you the tools rather than a list of rules of thumb.</p><h2 id="measuring-with-stdchrono"><a class="header" href="#measuring-with-stdchrono">Measuring with std::chrono</a></h2><p>C++ provides a portable, monotonic clock in the standard library: <code>std::chrono::steady_clock</code>. Unlike <code>std::chrono::system_clock</code>, the steady clock never jumps because of adjustments to the system time. Use <code>steady_clock::now()</code> before and after the code region and compute the difference. The following inline example measures the time taken to execute a trivial loop.</p><pre><code class="language-cpp">#include <chrono>#include <iostream>
int main() { auto start = std::chrono::steady_clock::now(); volatile int sum = 0; // prevent optimisation of the loop body for (int i = 0; i < 10'000'000; ++i) { sum += i; } auto end = std::chrono::steady_clock::now(); auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start); std::cout << "elapsed: " << elapsed.count() << " µs\n"; return 0;}</code></pre><p>The program prints a single line such as <code>elapsed: 12345 µs</code>. The unit is a concrete, reproducible quantity that the test harness can match. Because <code>steady_clock</code> is monotonic, the measurement is not affected by clock adjustments, NTP updates, or daylight-saving changes. This makes it the preferred tool for micro-benchmarking code that runs for a short period.</p><p>For more reliable numbers, run the loop several times and record each measurement. Compute the median or the minimum value. The minimum discards noise from background activity, while the median reduces the impact of outliers. Warm up the code once before timing to let the processor reach its steady frequency and to populate caches. A typical benchmarking harness therefore performs a warm-up iteration, followed by a fixed number of timed iterations, and finally reports the best or median elapsed time.</p><p>The <code>volatile</code> in the timing loop is important. Without it the compiler can see that the loop has no observable effect and delete it entirely under the as-if rule, making the measured time zero. <code>volatile</code> forces the writes to happen, so the loop measures real work. The same trick is why micro-benchmarks accumulate into a <code>volatile</code> sink rather than returning a value that is never used.</p><p>A single measurement is not a number you can trust. Run the workload several times and report the spread, because a two-fold difference between runs is common under system noise.</p><h2 id="the-as-if-rule-and-optimizer-levels"><a class="header" href="#the-as-if-rule-and-optimizer-levels">The as-if rule and optimizer levels</a></h2><p>The C++ as-if rule permits the compiler to transform any program as long as the observable behaviour is unchanged. Observable behaviour consists of the program’s side effects on volatile objects, file I/O, and the values returned from <code>main</code>. Therefore a build compiled with <code>-O2</code> or <code>-O3</code> can reorder statements, inline functions, or eliminate dead code, provided the resulting side effects match the source semantics. A build with <code>-O0</code> performs almost no optimisation. It preserves the source order but does not represent the performance of a real-world binary. Benchmarking an unoptimised build therefore yields a number that the production binary will never exhibit. The meaningful comparison is always between two programs built with the same optimisation level.</p><p>Consider a function that adds two integers and returns the result. With <code>-O0</code> the compiler emits a call to the function, a load of each argument, an addition, and a return. With <code>-O2</code> the compiler can inline the function, keep the arguments in registers, and avoid the call entirely. The observable result, the returned sum, is identical, so the transformation is permitted. Benchmarks that report the speed of the <code>-O0</code> version therefore mislead. They measure the cost of the extra call and the lack of register allocation, not the intrinsic cost of the algorithm.</p><h2 id="move-vs-copy"><a class="header" href="#move-vs-copy">Move vs copy</a></h2><p>Moving a value transfers ownership of its resources without allocating or copying the underlying data. Copying, by contrast, must duplicate the resources. The instrumented <code>Counter</code> struct below records how many copy and move constructions occur. The <code>book_example</code> registration verifies the printed statistics. By examining the counters you can see that a move operation incurs far less work than a copy, especially when the underlying type manages heap memory or other expensive resources. This observation underlies the design of many standard library containers that prefer move over copy when they can.</p><pre><code class="language-cpp">#include <iostream>#include <utility>
struct Counter { static int copies; static int moves; Counter() = default; Counter(const Counter&) { ++copies; } Counter(Counter&&) noexcept { ++moves; } Counter& operator=(const Counter&) = delete; Counter& operator=(Counter&&) = delete; ~Counter() = default;};
int Counter::copies = 0;int Counter::moves = 0;
int main() { Counter a; Counter b = a; // copy Counter c = std::move(a); // move std::cout << "copy: " << Counter::copies << " move: " << Counter::moves << "\n"; return 0;}</code></pre><p>Running the program yields a line such as <code>copy: 1 move: 1</code>. The numbers confirm that the explicit copy and explicit move each invoke a single constructor, and that the default-constructed object does not contribute to the counts. If you replace the copy with another move, the copy counter stays at zero, showing the performance advantage of move semantics in realistic code. In larger containers, moving a <code>std::vector</code> merely swaps its internal pointer and size, while copying allocates new storage and copies each element, an order of magnitude more work.</p><p>Move operations are <code>noexcept</code> for the standard containers, and that single word unlocks a real optimisation. <code>std::vector</code> uses the move constructor during growth only when it is guaranteed not to throw. If the move can throw, the vector has to copy instead, to keep the strong exception guarantee. Marking your own types’ move constructors <code>noexcept</code> is therefore not ceremony. It is what lets <code>vector</code> move them during reallocation rather than copy.</p><p>See Chapter 5 for a detailed comparison of move versus copy costs.</p><h2 id="copy-elision-and-rvo"><a class="header" href="#copy-elision-and-rvo">Copy elision and RVO</a></h2><p>When a function returns a prvalue of class type, the language permits the compiler to construct the result directly in the caller’s storage. This <em>copy-elision</em> eliminates both the copy and the move constructor calls. The classic case is the <em>return value optimisation</em> (RVO). The following example prints markers from the constructors and destructors. If elision occurs, only the constructor and destructor of the local object appear, and no copy or move messages are printed. This behaviour is guaranteed by the standard when the criteria for NRVO are met, and modern compilers perform it even at <code>-O0</code>.</p><pre><code class="language-cpp">#include <iostream>#include <utility>
struct Marker { static int copies; static int moves; Marker() { std::cout << "ctor\n"; } Marker(const Marker&) { ++copies; std::cout << "copy\n"; } Marker(Marker&&) noexcept { ++moves; std::cout << "move\n"; } Marker& operator=(const Marker&) = delete; Marker& operator=(Marker&&) = delete; ~Marker() { std::cout << "dtor\n"; }};
int Marker::copies = 0;int Marker::moves = 0;
Marker make_marker() { Marker m; // ctor return m; // should be elided, no copy/move}
int main() { Marker x = make_marker(); // elision expected (void)x; std::cerr << "copies=" << Marker::copies << " moves=" << Marker::moves << "\n"; return 0;}</code></pre><p>The test harness expects the output to contain <code>copies=0 moves=0</code>. When the compiler performs RVO, the program’s output satisfies that expectation, demonstrating that the return did not incur any additional construction. If you deliberately disable copy-elision, for example by compiling with <code>-fno-elide-constructors</code>, the output changes to show a copy or move, which is useful for educational purposes but not representative of typical production builds.</p><p>Guaranteed copy elision, in effect since C++17, means a prvalue return does not even require the type to have a move constructor. A function that returns a prvalue of an immovable type still compiles and constructs the result in place. This is why returning a <code>std::vector</code> or a large struct by value is not just idiomatic but the fastest option. There is no copy and no move, only direct construction in the caller’s storage.</p><p>Chapter 18 showed that copy elision and RVO can remove all copy/move operations, making return‑by‑value the fastest way to deliver a result.</p><h2 id="container-big-o-review"><a class="header" href="#container-big-o-review">Container big-O review</a></h2><p>Choosing the right container yields the highest performance gain in most programs. <code>std::vector</code> grows by amortised constant time. Each <code>push_back</code> is O(1) on average, but occasional reallocation costs O(n). Reserving capacity with <code>reserve(n)</code> eliminates those reallocations and therefore reduces the worst-case overhead. Associative containers differ. <code>std::map</code> provides ordered lookup in O(log n), while <code>std::unordered_map</code> offers average constant-time lookup, O(1), at the cost of higher memory usage and possible hash collisions. Understanding these complexities lets the programmer place the most expensive operations in the cheapest container. For example, building a large list of results is usually fastest with a <code>vector</code> that has been pre-reserved.</p><p>When a container holds objects that are expensive to move or copy, the cost of reallocation becomes significant. An optimisation is to store <code>std::unique_ptr<T></code> in a <code>vector</code> and reserve enough space before filling it. This avoids repeated allocations of <code>T</code> and eliminates the need to move <code>T</code> objects during reallocation, because only the pointers are moved.</p><p>Big-O notation hides constant factors, which are real. An <code>unordered_map</code> is O(1) per lookup but has a large constant and high memory overhead, so for a handful of keys a linear scan of a small <code>vector</code> is faster. The rule is to choose by the shape of the workload, then confirm with a measurement, which brings the chapter’s central lesson back around. Choosing a container is a one-line change with large leverage, which is why it comes before micro-optimising a loop body.</p><h2 id="reading-a-hot-loop"><a class="header" href="#reading-a-hot-loop">Reading a hot loop</a></h2><p>On Linux the profiler <code>perf</code> records CPU cycles, cache-miss events, and instruction retirements. On macOS the <code>Instruments</code> app provides similar metrics, including cache misses and allocations. When analysing a hot loop, look for a high proportion of cache-miss cycles, frequent allocations inside the loop body, and indirect calls such as virtual dispatch. Reducing cache misses involves improving data locality, for example by storing related objects contiguously in a <code>vector</code> or by using a struct-of-arrays layout. Eliminating allocations can be achieved with <code>reserve</code> or by reusing objects that are allocated once outside the loop. Virtual calls can be replaced by static polymorphism, by <code>std::function_ref</code>, or by inlining small call sites. The point is not to collect profiles but to find one or two dominant costs, because fixing the single hottest line usually beats optimising twenty small ones.</p><p>A typical workflow is:</p><ol><li>Run the program under <code>perf record -g ./a.out</code> or with Instruments’ time profiler.</li><li>Identify the hottest functions from the flame graph.</li><li>Drill into those functions to see which lines cause the most cache-miss or allocation events.</li><li>Refactor the code to improve locality, pre-allocate storage, or replace virtual calls.</li><li>Re-run the profiler to verify that the hot spots have diminished.</li></ol><h2 id="try-this"><a class="header" href="#try-this">Try this</a></h2><p>Predict whether calling <code>reserve(n)</code> on a <code>std::vector<std::unique_ptr<Node>></code> that stores a binary tree will reduce the total runtime of a breadth-first construction loop. Measure the loop with <code>std::chrono::steady_clock</code> as shown earlier, print the elapsed time, and compare the two runs. Record the result as <code>elapsed without reserve: X µs</code> and <code>elapsed with reserve: Y µs</code>. The experiment demonstrates the real impact of pre-allocation on a realistic data-structure workload.</p>
</main>
<nav class="nav-wrapper" aria-label="Page navigation"> <!-- Mobile navigation buttons --> <a rel="prev" href="ch28-speaking-c.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="appendix-a.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a>
<div style="clear: both"></div> </nav> </div> </div>
<nav class="nav-wide-wrapper" aria-label="Page navigation"> <a rel="prev" href="ch28-speaking-c.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M41.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.3 256 246.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z"/></svg></span> </a>
<a rel="next prefetch" href="appendix-a.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right"> <span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M278.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-160 160c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L210.7 256 73.4 118.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l160 160z"/></svg></span> </a> </nav>
</div>
<template id=fa-eye><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M288 32c-80.8 0-145.5 36.8-192.6 80.6C48.6 156 17.3 208 2.5 243.7c-3.3 7.9-3.3 16.7 0 24.6C17.3 304 48.6 356 95.4 399.4C142.5 443.2 207.2 480 288 480s145.5-36.8 192.6-80.6c46.8-43.5 78.1-95.4 93-131.1c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C433.5 68.8 368.8 32 288 32zM432 256c0 79.5-64.5 144-144 144s-144-64.5-144-144s64.5-144 144-144s144 64.5 144 144zM288 192c0 35.3-28.7 64-64 64c-11.5 0-22.3-3-31.6-8.4c-.2 2.8-.4 5.5-.4 8.4c0 53 43 96 96 96s96-43 96-96s-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6z"/></svg></span></template> <template id=fa-eye-slash><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zM223.1 149.5C248.6 126.2 282.7 112 320 112c79.5 0 144 64.5 144 144c0 24.9-6.3 48.3-17.4 68.7L408 294.5c5.2-11.8 8-24.8 8-38.5c0-53-43-96-96-96c-2.8 0-5.6 .1-8.4 .4c5.3 9.3 8.4 20.1 8.4 31.6c0 10.2-2.4 19.8-6.6 28.3l-90.3-70.8zm223.1 298L373 389.9c-16.4 6.5-34.3 10.1-53 10.1c-79.5 0-144-64.5-144-144c0-6.9 .5-13.6 1.4-20.2L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5z"/></svg></span></template> <template id=fa-copy><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z"/></svg></span></template> <template id=fa-play><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg></span></template> <template id=fa-clock-rotate-left><span class=fa-svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path d="M75 75L41 41C25.9 25.9 0 36.6 0 57.9V168c0 13.3 10.7 24 24 24H134.1c21.4 0 32.1-25.9 17-41l-30.8-30.8C155 85.5 203 64 256 64c106 0 192 86 192 192s-86 192-192 192c-40.8 0-78.6-12.7-109.7-34.4c-14.5-10.1-34.4-6.6-44.6 7.9s-6.6 34.4 7.9 44.6C151.2 495 201.7 512 256 512c141.4 0 256-114.6 256-256S397.4 0 256 0C185.3 0 121.3 28.7 75 75zm181 53c-13.3 0-24 10.7-24 24V256c0 6.4 2.5 12.5 7 17l72 72c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-65-65V152c0-13.3-10.7-24-24-24z"/></svg></span></template>
<script> window.playground_copyable = true; </script>
<script src="elasticlunr-ef4e11c1.min.js"></script> <script src="mark-09e88c2c.min.js"></script> <script src="searcher-09f2665d.js"></script>
<script src="clipboard-1626706a.min.js"></script> <script src="highlight-abc7f01d.js"></script> <script src="book-609e4cb8.js"></script>
<!-- Custom JS scripts -->
</div> </body></html>