bgc_a4_c_2
bgc_a4_c_2
1 Foreword 1
1.1 Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 How to Read This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Platform and Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Official Homepage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5 Email Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.6 Mirroring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.7 Note for Translators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.8 Copyright and Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.9 Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Hello, World! 5
2.1 What to Expect from C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Hello, World! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Compilation Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4 Building with gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Building with clang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.6 Building from IDEs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.7 C Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 Functions 25
4.1 Passing by Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 Function Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3 Empty Parameter Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5 Pointers—Cower In Fear! 29
5.1 Memory and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2 Pointer Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
ii
CONTENTS iii
5.3 Dereferencing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.4 Passing Pointers as Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.5 The NULL Pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.6 A Note on Declaring Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.7 sizeof and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6 Arrays 37
6.1 Easy Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.2 Getting the Length of an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.3 Array Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.4 Out of Bounds! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.5 Multidimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.6 Arrays and Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.6.1 Getting a Pointer to an Array . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.6.2 Passing Single Dimensional Arrays to Functions . . . . . . . . . . . . . . . . . 42
6.6.3 Changing Arrays in Functions . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.6.4 Passing Multidimensional Arrays to Functions . . . . . . . . . . . . . . . . . . 44
7 Strings 45
7.1 String Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.2 String Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.3 String Variables as Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.4 String Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.5 Getting String Length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.6 String Termination . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
7.7 Copying a String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
8 Structs 51
8.1 Declaring a Struct . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.2 Struct Initializers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.3 Passing Structs to Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
8.4 The Arrow Operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
8.5 Copying and Returning structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
8.6 Comparing structs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
9 File Input/Output 55
9.1 The FILE* Data Type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
9.2 Reading Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
9.3 End of File: EOF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
9.3.1 Reading a Line at a Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
9.4 Formatted Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.5 Writing Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
9.6 Binary File I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
9.6.1 struct and Number Caveats . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
13 Scope 83
13.1 Block Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
13.1.1 Where To Define Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
13.1.2 Variable Hiding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13.2 File Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
13.3 for-loop Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
13.4 A Note on Function Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
27.6 A Quick Note on UTF-8 Before We Swerve into the Weeds . . . . . . . . . . . . . . 192
27.7 Different Character Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
27.7.1 Multibyte Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
27.7.2 Wide Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
27.8 Using Wide Characters and wchar_t . . . . . . . . . . . . . . . . . . . . . . . . . . 194
27.8.1 Multibyte to wchar_t Conversions . . . . . . . . . . . . . . . . . . . . . . . . 195
27.9 Wide Character Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.1 wint_t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.2 I/O Stream Orientation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.3 I/O Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
27.9.4 Type Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
27.9.5 String and Memory Copying Functions . . . . . . . . . . . . . . . . . . . . . 197
27.9.6 String and Memory Comparing Functions . . . . . . . . . . . . . . . . . . . . 197
27.9.7 String Searching Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
27.9.8 Length/Miscellaneous Functions . . . . . . . . . . . . . . . . . . . . . . . . . 198
27.9.9 Character Classification Functions . . . . . . . . . . . . . . . . . . . . . . . . 198
27.10 Parse State, Restartable Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
27.11 Unicode Encodings and C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
27.11.1 UTF-8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
27.11.2 UTF-16, UTF-32, char16_t, and char32_t . . . . . . . . . . . . . . . . . . . 201
27.11.3 Multibyte Conversions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
27.11.4 Third-Party Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202
31 goto 219
31.1 A Simple Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
31.2 Labeled continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
31.3 Bailing Out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
31.4 Labeled break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
31.5 Multi-level Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
31.6 Tail Call Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
viii CONTENTS
39 Multithreading 261
39.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
39.2 Things You Can Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261
39.3 Data Races and the Standard Library . . . . . . . . . . . . . . . . . . . . . . . . . . 262
39.4 Creating and Waiting for Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
39.5 Detaching Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
39.6 Thread Local Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
39.6.1 _Thread_local Storage-Class . . . . . . . . . . . . . . . . . . . . . . . . . 268
39.6.2 Another Option: Thread-Specific Storage . . . . . . . . . . . . . . . . . . . . 269
39.7 Mutexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 270
39.7.1 Different Mutex Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
39.8 Condition Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274
39.8.1 Timed Condition Wait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
39.8.2 Broadcast: Wake Up All Waiting Threads . . . . . . . . . . . . . . . . . . . . 278
39.9 Running a Function One Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
40 Atomics 279
40.1 Testing for Atomic Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
40.2 Atomic Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
40.3 Synchronization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
40.4 Acquire and Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
40.5 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
40.6 Atomic Assignments and Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
40.7 Library Functions that Automatically Synchronize . . . . . . . . . . . . . . . . . . . 285
40.8 Atomic Type Specifier, Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
40.9 Lock-Free Atomic Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
40.9.1 Signal Handlers and Lock-Free Atomics . . . . . . . . . . . . . . . . . . . . . 288
40.10 Atomic Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
40.11 Atomic structs and unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
40.12 Atomic Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
40.13 Memory Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
40.13.1 Sequential Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.2 Acquire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.3 Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.4 Consume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.5 Acquire/Release . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.13.6 Relaxed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
40.14 Fences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
40.15 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
Foreword
No point in wasting words here, folks, let’s jump straight into the C code:
E((ck?main((z?(stat(M,&t)?P+=a+'{'?0:3:
execv(M,k),a=G,i=P,y=G&255,
sprintf(Q,y/'@'-3?A(*L(V(%d+%d)+%d,0)
1.1 Audience
This guide assumes that you’ve already got some programming knowledge under your belt from another
language, such as Python2 , JavaScript3 , Java4 , Rust5 , Go6 , Swift7 , etc. (Objective-C8 devs will have a
particularly easy time of it!)
We’re going to assume you know what variables are, what loops do, how functions work, and so on.
If that’s not you for whatever reason the best I can hope to provide is some honest entertainment for your
reading pleasure. The only thing I can reasonably promise is that this guide won’t end on a cliffhanger…
or will it?
1
2 Chapter 1. Foreword
And no matter your skill level, the reference part is there with complete examples of the standard library
function calls to help refresh your memory whenever needed. Good for reading over a bowl of cereal or
other time.
Finally, glancing at the index (if you’re reading the print version), the reference section entries are itali-
cized.
1.6 Mirroring
You are more than welcome to mirror this site, whether publicly or privately. If you publicly mirror the
site and want me to link to it from the main page, drop me a line at [email protected].
9
https://en.wikipedia.org/wiki/ANSI_C
10
https://en.wikipedia.org/wiki/POSIX
11
https://visualstudio.microsoft.com/vs/community/
12
https://docs.microsoft.com/en-us/windows/wsl/install-win10
13
https://developer.apple.com/xcode/
14
https://beej.us/guide/bgc/
1.7. Note for Translators 3
1.9 Dedication
The hardest things about writing these guides are:
• Learning the material in enough detail to be able to explain it
• Figuring out the best way to explain it clearly, a seemingly-endless iterative process
• Putting myself out there as a so-called authority, when really I’m just a regular human trying to
make sense of it all, just like everyone else
• Keeping at it when so many other things draw my attention
A lot of people have helped me through this process, and I want to acknowledge those who have made
this book possible.
• Everyone on the Internet who decided to help share their knowledge in one form or another. The
free sharing of instructive information is what makes the Internet the great place that it is.
• The volunteers at cppreference.com15 who provide the bridge that leads from the spec to the real
world.
• The helpful and knowledgeable folks on comp.lang.c16 and r/C_Programming17 who got me through
the tougher parts of the language.
• Everyone who submitted corrections and pull-requests on everything from misleading instructions
to typos.
Thank you! ♥
15
https://en.cppreference.com/
16
https://groups.google.com/g/comp.lang.c
17
https://www.reddit.com/r/C_Programming/
4 Chapter 1. Foreword
Chapter 2
Hello, World!
5
6 Chapter 2. Hello, World!
So get ready for a rollicking adventure as close to the core of the computer as you can get without assembly,
in the most influential computer language of all time7 . Hang on!
3 #include <stdio.h>
4
5 int main(void)
6 {
7 printf("Hello, World!\n"); // Actually do the work here
8 }
We’re going to don our long-sleeved heavy-duty rubber gloves, grab a scalpel, and rip into this thing to
see what makes it tick. So, scrub up, because here we go. Cutting very gently…
Let’s get the easy thing out of the way: anything between the digraphs /* and */ is a comment and will
be completely ignored by the compiler. Same goes for anything on a line after a //. This allows you
to leave messages to yourself and others, so that when you come back and read your code in the distant
future, you’ll know what the heck it was you were trying to do. Believe me, you will forget; it happens.
Now, what is this #include? GROSS! Well, it tells the C Preprocessor to pull the contents of another file
and insert it into the code right there.
Wait—what’s a C Preprocessor? Good question. There are two stages8 to compilation: the preprocessor
and the compiler. Anything that starts with pound sign, or “octothorpe”, (#) is something the preprocessor
operates on before the compiler even gets started. Common preprocessor directives, as they’re called, are
#include and #define. More on that later.
Before we go on, why would I even begin to bother pointing out that a pound sign is called an octothorpe?
The answer is simple: I think the word octothorpe is so excellently funny, I have to gratuitously spread its
name around whenever I get the opportunity. Octothorpe. Octothorpe, octothorpe, octothorpe.
So anyway. After the C preprocessor has finished preprocessing everything, the results are ready for
the compiler to take them and produce assembly code9 , machine code10 , or whatever it’s about to do.
Machine code is the “language” the CPU understands, and it can understand it very rapidly. This is one
of the reasons C programs tend to be quick.
Don’t worry about the technical details of compilation for now; just know that your source runs through
the preprocessor, then the output of that runs through the compiler, then that produces an executable for
you to run.
What about the rest of the line? What’s <stdio.h>? That is what is known as a header file. It’s the
dot-h at the end that gives it away. In fact it’s the “Standard I/O” (stdio) header file that you will grow
to know and love. It gives us access to a bunch of I/O functionality11 . For our demo program, we’re
outputting the string “Hello, World!”, so we in particular need access to the printf() function to do this.
The <stdio.h> file gives us this access. Basically, if we tried to use without #include <stdio.h>, the
compiler would have complained to us about it.
How did I know I needed to #include <stdio.h> for printf()? Answer: it’s in the documentation.
If you’re on a Unix system, man 3 printf and it’ll tell you right at the top of the man page what header
files are required. Or see the reference section in this book. :-)
7
I know someone will fight me on that, but it’s gotta be at least in the top three, right?
8
Well, technically there are more than two, but hey, let’s pretend there are two—ignorance is bliss, right?
9
https://en.wikipedia.org/wiki/Assembly_language
10
https://en.wikipedia.org/wiki/Machine_code
11
Technically, it contains preprocessor directives and function prototypes (more on that later) for common input and output needs.
2.3. Compilation Details 7
Holy moly. That was all to cover the first line! But, let’s face it, it has been completely dissected. No
mystery shall remain!
So take a breather…look back over the sample code. Only a couple easy lines to go.
Welcome back from your break! I know you didn’t really take a break; I was just humoring you.
The next line is main(). This is the definition of the function main(); everything between the squirrelly
braces ({ and }) is part of the function definition.
(How do you call a different function, anyway? The answer lies in the printf() line, but we’ll get to
that in a minute.)
Now, the main function is a special one in many ways, but one way stands above the rest: it is the function
that will be called automatically when your program starts executing. Nothing of yours gets called before
main(). In the case of our example, this works fine since all we want to do is print a line and exit.
Oh, that’s another thing: once the program executes past the end of main(), down there at the closing
squirrelly brace, the program will exit, and you’ll be back at your command prompt.
So now we know that that program has brought in a header file, stdio.h, and declared a main() function
that will execute when the program is started. What are the goodies in main()?
I am so happy you asked. Really! We only have the one goodie: a call to the function printf(). You
can tell this is a function call and not a function definition in a number of ways, but one indicator is the
lack of squirrelly braces after it. And you end the function call with a semicolon so the compiler knows
it’s the end of the expression. You’ll be putting semicolons after almost everything, as you’ll see.
You’re passing one argument to the function printf(): a string to be printed when you call it. Oh,
yeah—we’re calling a function! We rock! Wait, wait—don’t get cocky. What’s that crazy \n at the end
of the string? Well, most characters in the string will print out just like they are stored. But there are
certain characters that you can’t print on screen well that are embedded as two-character backslash codes.
One of the most popular is \n (read “backslash-N”) that corresponds to the newline character. This is the
character that causes further printing to continue at the beginning of the next line instead of the current.
It’s like hitting return at the end of the line.
So copy that code into a file called hello.c and build it. On a Unix-like platform (e.g. Linux, BSD, Mac,
or WSL), from the command line you’ll build with a command like so:
gcc -o hello hello.c
(The leading ./ tells the shell to “run from the current directory”.)
And see what happens:
Hello, World!
machine can execute. Java devs are used to compilation, but that produces bytecode for the Java Virtual
Machine.
When compiling C, machine code is generated. This is the 1s and 0s that can be executed directly and
speedily by the CPU.
Languages that typically aren’t compiled are called interpreted languages. But as we men-
tioned with Java and Python, they also have a compilation step. And there’s no rule saying
that C can’t be interpreted. (There are C interpreters out there!) In short, it’s a bunch of gray
areas. Compilation in general is just taking source code and turning it into another, more
easily-executed form.
The C compiler is the program that does the compilation.
As we’ve already said, gcc is a compiler that’s installed on a lot of Unix-like operating systems12 . And
it’s commonly run from the command line in a terminal, but not always. You can run it from your IDE,
as well.
So how do we do command line builds?
The -o means “output to this file”13 . And there’s hello.c at the end, the name of the file we want to
compile.
If your source is broken up into multiple files, you can compile them all together (almost as if they were
one file, but the rules are actually more complex than that) by putting all the .c files on the command line:
gcc -o awesomegame ui.c characters.c npc.c items.c
2.7 C Versions
C has come a long way over the years, and it had many named version numbers to describe which dialect
of the language you’re using.
These generally refer to the year of the specification.
The most famous are C89, C99, C11, and C2x. We’ll focus on the latter in this book.
But here’s a more complete table:
Version Description
K&R C 1978, the original. Named after Brian Kernighan and Dennis Ritchie.
Ritchie designed and coded the language, and Kernighan co-authored the
book on it. You rarely see original K&R code today. If you do, it’ll look
odd, like Middle English looks odd to modern English readers.
C89, ANSI C, C90 In 1989, the American National Standards Institute (ANSI) produced a C
language specification that set the tone for C that persists to this day. A
year later, the reins were handed to the International Organization for
Standardization (ISO) that produced the identical C90.
C95 A rarely-mentioned addition to C89 that included wide character support.
C99 The first big overhaul with lots of language additions. The thing most
people remember is the addition of //-style comments. This is the most
popular version of C in use as of this writing.
C11 This major version update includes Unicode support and multi-threading.
Be advised that if you start using these language features, you might be
sacrificing portability with places that are stuck in C99 land. But, honestly,
1999 is getting to be a while back now.
C17, C18 Bugfix update to C11. C17 seems to be the official name, but the
publication was delayed until 2018. As far as I can tell, these two are
interchangeable, with C17 being preferred.
C2x What’s coming next! Expected to eventually become C21.
You can force GCC to use one of these standards with the -std= command line argument. If you want it
to be picky about the standard, add -pedantic.
For example:
gcc -std=c11 -pedantic foo.c
For this book, I compile programs for C2x with all warnings set:
gcc -Wall -Wextra -std=c2x -pedantic foo.c
10 Chapter 2. Hello, World!
Chapter 3
3.1 Variables
It’s said that “variables hold values”. But another way to think about it is that a variable is a human-
readable name that refers to some data in memory.
We’re going to take a second here and take a peek down the rabbit hole that is pointers. Don’t worry about
it.
You can think of memory as a big array of bytes1 . Data is stored in this “array”2 . If a number is larger than
a single byte, it is stored in multiple bytes. Because memory is like an array, each byte of memory can be
referred to by its index. This index into memory is also called an address, or a location, or a pointer.
When you have a variable in C, the value of that variable is in memory somewhere, at some address. Of
course. After all, where else would it be? But it’s a pain to refer to a value by its numeric address, so we
make a name for it instead, and that’s what the variable is.
The reason I’m bringing all this up is twofold:
1. It’s going to make it easier to understand pointer variables later—they’re variables that hold the
address of other variables!
2. Also, it’s going to make it easier to understand pointers later.
So a variable is a name for some data that’s stored in memory at some address.
11
12 Chapter 3. Variables and Statements
• You can’t start a variable name with an underscore followed by a capital A-Z.
For Unicode, just try it. There are some rules in the spec in §D.2 that talk about which Unicode codepoint
ranges are allowed in which parts of identifiers, but that’s too much to write about here and is probably
something you’ll never have to think about anyway.
C makes an effort to convert automatically between most numeric types when you ask it to. But other
than that, all conversions are manual, notably between string and numeric.
Almost all of the types in C are variants on these types.
Before you can use a variable, you have to declare that variable and tell C what type the variable holds.
Once declared, the type of variable cannot be changed later at runtime. What you set it to is what it is
until it falls out of scope and is reabsorbed into the universe.
Let’s take our previous “Hello, world” code and add a couple variables to it:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i; // Holds signed integers, e.g. -3, -2, 0, 1, 10
6 float f; // Holds signed floating point numbers, e.g. -3.1416
7
There! We’ve declared a couple of variables. We haven’t used them yet, and they’re both uninitialized.
One holds an integer number, and the other holds a floating point number (a real number, basically, if you
have a math background).
Uninitialized variables have indeterminate value4 . They have to be initialized or else you must assume
they contain some nonsense number.
This is one of the places C can “get you”. Much of the time, in my experience, the indeter-
minate value is zero… but it can vary from run to run! Never assume the value will be zero,
even if you see it is. Always explicitly initialize variables to some value before you use them5 .
What’s this? You want to store some numbers in those variables? Insanity!
Let’s go ahead and do that:
1 int main(void)
2 {
3 int i;
3
Read this as “pointer to a char” or “char pointer”. “Char” for character. Though I can’t find a study, it seems anecdotally most
people pronounce this as “char”, a minority say “car”, and a handful say “care”. We’ll talk more about pointers later.
4
Colloquially, we say they have “random” values, but they aren’t truly—or even pseudo-truly—random numbers.
5
This isn’t strictly 100% true. When we get to learning about static storage duration, you’ll find the some variables are initialized
to zero automatically. But the safe thing to do is always initialize them.
3.1. Variables 13
7 printf("Hello, World!\n");
8 }
3 int main(void)
4 {
5 int i = 2;
6 float f = 3.14;
7 char *s = "Hello, world!"; // char * ("char pointer") is the string type
8
In this way, printf() might be similar to various types of format strings or parameterized strings in other
languages you’re familiar with.
Historically, C didn’t have a Boolean type, and some might argue it still doesn’t.
In C, 0 means “false”, and non-zero means “true”.
So 1 is true. And -37 is true. And 0 is false.
You can just declare Boolean types as ints:
int x = 1;
if (x) {
printf("x is true!\n");
}
If you #include <stdbool.h>, you also get access to some symbolic names that might make things
look more familiar, namely a bool type and true and false values:
1 #include <stdio.h>
2 #include <stdbool.h>
3
4 int main(void) {
5 bool x = true;
14 Chapter 3. Variables and Statements
7 if (x) {
8 printf("x is true!\n");
9 }
10 }
But these are identical to using integer values for true and false. They’re just a facade to make things look
nice.
3.2.1 Arithmetic
Hopefully these are familiar:
i = i + 3; // Addition (+) and assignment (=) operators, add 3 to i
i = i - 8; // Subtraction, subtract 8 from i
i = i * 9; // Multiplication
i = i / 2; // Division
i = i % 5; // Modulo (division remainder)
There are shorthand variants for all of the above. Each of those lines could more tersely be written as:
i += 3; // Same as "i = i + 3", add 3 to i
i -= 8; // Same as "i = i - 8"
i *= 9; // Same as "i = i * 9"
i /= 2; // Same as "i = i / 2"
i %= 5; // Same as "i = i % 5"
There is no exponentiation. You’ll have to use one of the pow() function variants from math.h.
Let’s get into some of the weirder stuff you might not have in your other languages!
What a mess! You’ll get used to it the more you read it. To help out a bit, I’ll rewrite the above expression
using if statements:
// This expression:
if (x > 10)
y += 17;
else
y += 37;
Compare those two until you see each of the components of the ternary operator.
3.2. Operators and Expressions 15
The %s format specifier in printf() means print a string. If the expression x % 2 evaluates to 0, the
value of the entire ternary expression evaluates to the string "even". Otherwise it evaluates to the string
"odd". Pretty cool!
It’s important to note that the ternary operator isn’t flow control like the if statement is. It’s just an
expression that evaluates to a value.
but they’re more subtly different than that, the clever scoundrels.
Let’s take a look at this variant, pre-increment and pre-decrement:
++i; // Add one to i (pre-increment)
--i; // Subtract one from i (pre-decrement)
With pre-increment and pre-decrement, the value of the variable is incremented or decremented before
the expression is evaluated. Then the expression is evaluated with the new value.
With post-increment and post-decrement, the value of the expression is first computed with the value as-is,
and then the value is incremented or decremented after the value of the expression has been determined.
You can actually embed them in expressions, like this:
i = 10;
j = 5 + i++; // Compute 5 + i, _then_ increment i
This technique is used frequently with array and pointer access and manipulation. It gives you a way to
use the value in a variable, and also increment or decrement that value before or after it is used.
But by far the most common place you’ll see this is in a for loop:
for (i = 0; i < 10; i++)
printf("i is %d\n", i);
Seems a bit silly, since you could just replace the comma with a semicolon, right?
x = 10; y = 20; // First assign 10 to x, then 20 to y
But that’s a little different. The latter is two separate expressions, while the former is a single expression!
With the comma operator, the value of the comma expression is the value of the rightmost expression:
x = 1, 2, 3;
But even that’s pretty contrived. One common place the comma operator is used is in for loops to do
multiple things in each section of the statement:
for (i = 0, j = 10; i < 100; i++, j++)
printf("%d, %d\n", i, j);
Don’t mix up assignment = with comparison ==! Use two equals to compare, one to assign.
We can use the comparison expressions with if statements:
if (a <= 10)
printf("Success!\n");
! has higher precedence than the other Boolean operators, so we have to use parentheses in that case.
if (x >= 12)
printf("x is not less than 12\n");
Remember: it’s the size in bytes of the type of the expression, not the size of the expression itself. That’s
why the size of 2+7 is the same as the size of a—they’re both type int. We’ll revisit this number 4 in the
very next block of code…
…Where we’ll see you can take the sizeof a type (note the parentheses are required around a type name,
unlike an expression):
printf("%zu\n", sizeof(int)); // Prints 4 on my system
printf("%zu\n", sizeof(char)); // Prints 1 on all systems
It’s important to note that sizeof is a compile-time operation7 . The result of the expression is determined
entirely at compile-time, not at runtime.
We’ll make use of this later on.
After something like an if or while statement, you can either put a single statement to be executed, or a
block of statements to all be executed in sequence.
This is also sometimes written on a separate line. (Whitespace is largely irrelevant in C—it’s not like
Python.)
if (x == 10)
printf("x is 10\n");
But what if you want multiple things to happen due to the conditional? You can use squirrelly braces to
mark a block or compound statement.
if (x == 10) {
printf("x is 10\n");
printf("And also this happens when x is 10\n");
}
It’s a really common style to always use squirrelly braces even if they aren’t necessary:
if (x == 10) {
printf("x is 10\n");
}
Some devs feel the code is easier to read and avoids errors like this where things visually look like they’re
in the if block, but actually they aren’t.
// BAD ERROR EXAMPLE
if (x == 10)
printf("This happens if x is 10\n");
printf("This happens ALWAYS\n"); // Surprise!! Unconditional!
while and for and the other looping constructs work the same way as the examples above. If you want
to do multiple things in a loop or after an if, wrap them up in squirrelly braces.
In other words, the if is going to run the one thing after the if. And that one thing can be a single
statement or a block of statements.
if (i > 10) {
printf("Yes, i is greater than 10.\n");
printf("And this will also print if i is greater than 10.\n");
}
In the example code, the message will print if i is greater than 10, otherwise execution continues to the next
line. Notice the squirrley braces after the if statement; if the condition is true, either the first statement
or expression right after the if will be executed, or else the collection of code in the squirlley braces after
the if will be executed. This sort of code block behavior is common to all statements.
Of course, because C is fun this way, you can also do something if the condition is false with an else
clause on your if:
3.3. Flow Control 19
int i = 99;
if (i == 10)
printf("i is 10!\n");
else {
printf("i is decidedly not 10.\n");
printf("Which irritates me a little, frankly.\n");
}
And you can even cascade these to test a variety of conditions, like this:
int i = 99;
if (i == 10)
printf("i is 10!\n");
else if (i == 20)
printf("i is 20!\n");
else if (i == 99) {
printf("i is 99! My favorite\n");
printf("I can't tell you how happy I am.\n");
printf("Really.\n");
}
else
printf("i is some crazy number I've never heard of.\n");
Though if you’re going that route, be sure to check out the switch statement for a potentially better
solution. The catch is switch only works with equality comparisons with constant numbers. The above
if-else cascade could check inequality, ranges, variables, or anything else you can craft in a conditional
expression.
Let’s do one!
// Print the following output:
//
// i is now 0!
// i is now 1!
// [ more of the same between 2 and 7 ]
// i is now 8!
// i is now 9!
i = 0;
printf("All done!\n");
That gets you a basic loop. C also has a for loop which would have been cleaner for that example.
A not-uncommon use of while is for infinite loops where you repeat while true:
20 Chapter 3. Variables and Statements
while (1) {
printf("1 is always true, so this repeats forever.\n");
}
They are basically the same, except if the loop condition is false on the first pass, do-while will execute
once, but while won’t execute at all. In other words, the test to see whether or not to execute the block
happens at the end of the block with do-while. It happens at the beginning of the block with while.
Let’s see by example:
// Using a while statement:
i = 10;
i = 10;
// this is executed once, because the loop condition is not checked until
// after the body of the loop runs:
do {
printf("do-while: i is %d\n", i);
i++;
} while (i < 10);
printf("All done!\n");
Notice that in both cases, the loop condition is false right away. So in the while, the loop fails, and
the following block of code is never executed. With the do-while, however, the condition is checked
after the block of code executes, so it always executes at least once. In this case, it prints the message,
increments i, then fails the condition, and continues to the “All done!” output.
The moral of the story is this: if you want the loop to execute at least once, no matter what the loop
condition, use do-while.
All these examples might have been better done with a for loop. Let’s do something less deterministic—
repeat until a certain random number comes up!
1 #include <stdio.h> // For printf
2 #include <stdlib.h> // For rand
3
4 int main(void)
5 {
6 int r;
7
8 do {
9 r = rand() % 100; // Get a random number between 0 and 99
10 printf("%d\n", r);
3.3. Flow Control 21
Side note: did you run that more than once? If you did, did you notice the same sequence of numbers
came up again. And again. And again? This is because rand() is a pseudorandom number generator that
must be seeded with a different number in order to generate a different sequence. Look up the srand()
function for more details.
This is a great loop if you know the number of times you want to loop in advance.
You could do the same thing using just a while loop, but the for loop can help keep the code cleaner.
Here are two pieces of equivalent code—note how the for loop is just a more compact representation:
// Print numbers between 0 and 9, inclusive...
i = 0;
while (i < 10) {
printf("i is %d\n", i);
i++;
}
That’s right, folks—they do exactly the same thing. But you can see how the for statement is a little more
compact and easy on the eyes. (JavaScript users will fully appreciate its C origins at this point.)
It’s split into three parts, separated by semicolons. The first is the initialization, the second is the loop
condition, and the third is what should happen at the end of the block if the loop condition is true. All
three of these parts are optional.
for (initialize things; loop if this is true; do this after each loop)
Note that the loop will not execute even a single time if the loop condition starts off false.
You can use the comma operator to do multiple things in each clause of the for loop!
for (i = 0, j = 999; i < 10; i++, j--) {
printf("%d, %d\n", i, j);
}
Let’s do an example where the user enters a number of goats and we print out a gut-feel of how many
goats that is.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int goat_count;
6
10 switch (goat_count) {
11 case 0:
12 printf("You have no goats.\n");
13 break;
14
15 case 1:
16 printf("You have a singular goat.\n");
17 break;
18
19 case 2:
20 printf("You have a brace of goats.\n");
21 break;
22
23 default:
24 printf("You have a bona fide plethora of goats!\n");
25 break;
26 }
27 }
In that example, if the user enters, say, 2, the switch will jump to the case 2 and execute from there.
When (if) it hits a break, it jumps out of the switch.
Also, you might see that default label there at the bottom. This is what happens when no cases match.
Every case, including default, is optional. And they can occur in any order, but it’s really typical for
default, if any, to be listed last.
• if-else can do things like relational conditionals like < and >= and floating point and other types,
while switch cannot.
There’s one more neat thing about switch that you sometimes see that is quite interesting: fall through.
Remember how break causes us to jump out of the switch?
Well, what happens if we don’t break?
Turns out we just keep on going into the next case! Demo!
switch (x) {
case 1:
printf("1\n");
// Fall through!
case 2:
printf("2\n");
break;
case 3:
printf("3\n");
break;
}
If x == 1, this switch will first hit case 1, it’ll print the 1, but then it just continues on to the next line
of code… which prints 2!
And then, at last, we hit a break so we jump out of the switch.
if x == 2, then we just hit the case 2, print 2, and break as normal.
Not having a break is called fall through.
ProTip: ALWAYS put a comment in the code where you intend to fall through, like I did above. It will
save other programmers from wondering if you meant to do that.
In fact, this is one of the common places to introduce bugs in C programs: forgetting to put a break in
your case. You gotta do it if you don’t want to just roll into the next case8 .
Earlier I said that switch works with integer types—keep it that way. Don’t use floating point or string
types in there. One loophole-ish thing here is that you can use character types because those are secretly
integers themselves. So this is perfectly acceptable:
char c = 'b';
switch (c) {
case 'a':
printf("It's 'a'!\n");
break;
case 'b':
printf("It's 'b'!\n");
break;
case 'c':
printf("It's 'c'!\n");
break;
}
Finally, you can use enums in switch since they are also integer types. But more on that in the enum
chapter.
8
This was considered such a hazard that the designers of the Go Programming Language made break the default; you have to
explicitly use Go’s fallthrough statement if you want to fall into the next case.
24 Chapter 3. Variables and Statements
Chapter 4
Functions
“Sir, not in an environment such as this. That’s why I’ve also been programmed for over
thirty secondary functions that—”
—C3PO, before being rudely interrupted, reporting a now-unimpressive number of additional
functions, Star Wars script
Very much like other languages you’re used to, C has the concept of functions.
Functions can accept a variety of arguments and return a value. One important thing, though: the argu-
ments and return value types are predeclared—because that’s how C likes it!
Let’s take a look at a function. This is a function that takes an int as an argument, and returns an int.
1 #include <stdio.h>
2
Before I forget, notice that I defined the function before I used it. If I hadn’t done that, the
compiler wouldn’t know about it yet when it compiles main() and it would have given an
unknown function call error. There is a more proper way to do the above code with function
prototypes, but we’ll talk about that later.
25
26 Chapter 4. Functions
5 void hello(void)
6 {
7 printf("Hello, world!\n");
8 }
9
10 int main(void)
11 {
12 hello(); // Prints "Hello, world!"
13 }
3 void increment(int a)
4 {
5 a++;
6 }
7
8 int main(void)
9 {
10 int i = 10;
11
12 increment(i);
13
At first glance, it looks like i is 10, and we pass it to the function increment(). There the value gets
incremented, so when we print it, it must be 11, right?
“Get used to disappointment.”
—Dread Pirate Roberts, The Princess Bride
But it’s not 11—it prints 10! How?
4.2. Function Prototypes 27
It’s all about the fact that the expressions you pass to functions get copied onto their corresponding pa-
rameters. The parameter is a copy, not the original.
So i is 10 out in main(). And we pass it to increment(). The corresponding parameter is called a in
that function.
And the copy happens, as if by assignment. Loosely, a = i. So at that point, a is 10. And out in main(),
i is also 10.
Then we increment a to 11. But we’re not touching i at all! It remains 10.
Finally, the function is complete. All its local variables are discarded (bye, a!) and we return to main(),
where i is still 10.
And we print it, getting 10, and we’re done.
This is why in the previous example with the plus_one() function, we returned the locally modified
value so that we could see it again in main().
Seems a little bit restrictive, huh? Like you can only get one piece of data back from a function, is what
you’re thinking. There is, however, another way to get data back; C folks call it passing by reference and
that’s a story we’ll tell another time.
But no fancy-schmancy name will distract you from the fact that EVERYTHING you pass to a function
WITHOUT EXCEPTION is copied into its corresponding parameter, and the function operates on that
local copy, NO MATTER WHAT. Remember that, even when we’re talking about this so-called passing
by reference.
5 int main(void)
6 {
7 int i;
8
12 i = foo();
13
If you don’t declare your function before you use it (either with a prototype or its definition), you’re
performing something called an implicit declaration. This was allowed in the first C standard (C89), and
that standard has rules about it, but is no longer allowed today. And there is no legitimate reason to rely
on it in new code.
You might notice something about the sample code we’ve been using… That is, we’ve been using the
good old printf() function without defining it or declaring a prototype! How do we get away with this
lawlessness? We don’t, actually. There is a prototype; it’s in that header file stdio.h that we included
with #include, remember? So we’re still legit, officer!
While the spec spells out that the behavior in this instance is as-if you’d indicated void (C11 §6.7.6.3¶14),
the void type is there for a reason. Use it.
But in the case of a function prototype, there is a significant difference between using void and not:
void foo();
void foo(void); // Not the same!
Leaving void out of the prototype indicates to the compiler that there is no additional information about
the parameters to the function. It effectively turns off all that type checking.
With a prototype definitely use void when you have an empty parameter list.
1
Never say “never”.
Chapter 5
Pointers—Cower In Fear!
Memory Fun Facts: When you have a data type (like your typical int) that uses more than a
byte of memory, the bytes that make up the data are always adjacent to one another in memory.
Sometimes they’re in the order that you expect, and sometimes they’re not3 . While C doesn’t
1
Typically. I’m sure there are exceptions out there in the dark corridors of computing history.
2
A byte is a number made up of no more than 8 binary digits, or bits for short. This means in decimal digits just like grandma
used to use, it can hold an unsigned number between 0 and 255, inclusive.
3
The order that bytes come in is referred to as the endianness of the number. The usual suspects are big-endian (with the most
significant byte first) and little-endian (with the most-significant byte last), or, uncommonly now, mixed-endian (with the most-
significant bytes somewhere else).
29
30 Chapter 5. Pointers—Cower In Fear!
guarantee any particular memory order (it’s platform-dependent), it’s still generally possible
to write code in a way that’s platform-independent where you don’t have to even consider
these pesky byte orderings.
So anyway, if we can get on with it and get a drum roll and some foreboding music playing for the
definition of a pointer, a pointer is a variable that holds an address. Imagine the classical score from
2001: A Space Odyssey at this point. Ba bum ba bum ba bum BAAAAH!
Ok, so maybe a bit overwrought here, yes? There’s not a lot of mystery about pointers. They are the
address of data. Just like an int variable can hold the value 12, a pointer variable can hold the address of
data.
This means that all these things mean the same thing, i.e. a number that represents a point in memory:
• Index into memory (if you’re thinking of memory like a big array)
• Address
• Location
I’m going to use these interchangeably. And yes, I just threw location in there because you can never have
enough words that mean the same thing.
And a pointer variable holds that address number. Just like a float variable might hold 3.14159.
Imagine you have a bunch of Post-it® notes all numbered in sequence with their address. (The first one
is at index numbered 0, the next at index 1, and so on.)
In addition to the number representing their positions, you can also write another number of your choice
on each. It could be the number of dogs you have. Or the number of moons around Mars…
…Or, it could be the index of another Post-it note!
If you have written the number of dogs you have, that’s just a regular variable. But if you wrote the index
of another Post-it in there, that’s a pointer. It points to the other note!
Another analogy might be with house addresses. You can have a house with certain qualities, yard, metal
roof, solar, etc. Or you could have the address of that house. The address isn’t the same as the house itself.
One’s a full-blown house, and the other is just a few lines of text. But the address of the house is a pointer
to that house. It’s not the house itself, but it tells you where to find it.
And we can do the same thing in the computer with data. You can have a data variable that’s holding some
value. And that value is in memory at some address. And you could have a different pointer variable hold
the address of that data variable.
It’s not the data variable itself, but, like with a house address, it tells us where to find it.
When we have that, we say we have a “pointer to” that data. And we can follow the pointer to access the
data itself.
(Though it doesn’t seem particularly useful yet, this all becomes indispensable when used with function
calls. Bear with me until we get there.)
So if we have an int, say, and we want a pointer to it, what we want is some way to get the address of
that int, right? After all, the pointer just holds the address of the data. What operator do you suppose
we’d use to find the address of the int?
Well, by a shocking surprise that must come as something of a shock to you, gentle reader, we use the
address-of operator (which happens to be an ampersand: “&”)to find the address of the data. Ampersand.
So for a quick example, we’ll introduce a new format specifier for printf() so you can print a pointer.
You know already how %d prints a decimal integer, yes? Well, %p prints a pointer. Now, this pointer is
going to look like a garbage number (and it might be printed in hexadecimal4 instead of decimal), but it is
merely the index into memory the data is stored in. (Or the index into memory that the first byte of data
is stored in, if the data is multi-byte.) In virtually all circumstances, including this one, the actual value of
the number printed is unimportant to you, and I show it here only for demonstration of the address-of
operator.
4
That is, base 16 with digits 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, and F.
5.2. Pointer Types 31
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i = 10;
6
If you’re curious, that hexadecimal number is 140,727,326,896,068 in decimal (base 10 just like Grandma
used to use). That’s the index into memory where the variable i’s data is stored. It’s the address of i. It’s
the location of i. It’s a pointer to i.
It’s a pointer because it lets you know where i is in memory. Like a home address written on a scrap of
paper tells you where you can find a particular house, this number indicates to us where in memory we
can find the value of i. It points to i.
Again, we don’t really care what the address’s exact number is, generally. We just care that it’s a pointer
to i.
Welcome back to another installment of Beej’s Guide. When we met last we were talking about how to
make use of pointers. Well, what we’re going to do is store a pointer off in a variable so that we can use it
later. You can identify the pointer type because there’s an asterisk (*) before the variable name and after
its type:
1 int main(void)
2 {
3 int i; // i's type is "int"
4 int *p; // p's type is "pointer to an int", or "int-pointer"
5 }
Hey, so we have here a variable that is a pointer type, and it can point to other ints. That is, it can hold
the address of other ints. We know it points to ints, since it’s of type int* (read “int-pointer”).
When you do an assignment into a pointer variable, the type of the right hand side of the assignment has
to be the same type as the pointer variable. Fortunately for us, when you take the address-of a variable,
the resultant type is a pointer to that variable type, so assignments like the following are perfect:
int i;
int *p; // p is a pointer, but is uninitialized and points to garbage
On the left of the assignment, we have a variable of type pointer-to-int (int*), and on the right side, we
have expression of type pointer-to-int since i is an int (because address-of int gives you a pointer to
int). The address of a thing can be stored in a pointer to that thing.
Get it? I know it still doesn’t quite make much sense since you haven’t seen an actual use for the pointer
variable, but we’re taking small steps here so that no one gets lost. So now, let’s introduce you to the
anti-address-of operator. It’s kind of like what address-of would be like in Bizarro World.
5.3 Dereferencing
A pointer variable can be thought of as referring to another variable by pointing to it. It’s rare you’ll hear
anyone in C land talking about “referring” or “references”, but I bring it up just so that the name of this
operator will make a little more sense.
When you have a pointer to a variable (roughly “a reference to a variable”), you can use the original
variable through the pointer by dereferencing the pointer. (You can think of this as “de-pointering” the
pointer, but no one ever says “de-pointering”.)
Back to our analogy, this is vaguely like looking at a home address and then going to that house.
Now, what do I mean by “get access to the original variable”? Well, if you have a variable called i, and
you have a pointer to i called p, you can use the dereferenced pointer p exactly as if it were the original
variable i!
You almost have enough knowledge to handle an example. The last tidbit you need to know is actually this:
what is the dereference operator? It’s actually called the indirection operator, because you’re accessing
values indirectly via the pointer. And it is the asterisk, again: *. Now, don’t get this confused with the
asterisk you used in the pointer declaration, earlier. They are the same character, but they have different
meanings in different contexts5 .
Here’s a full-blown example:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i;
6 int *p; // this is NOT a dereference--this is a type "int*"
7
10 i = 10; // i is now 10
11 *p = 20; // the thing p points to (namely i!) is now 20!!
12
Remember that p holds the address of i, as you can see where we did the assignment to p on line 8. What
the indirection operator does is tells the computer to use the object the pointer points to instead of using
the pointer itself. In this way, we have turned *p into an alias of sorts for i.
Great, but why? Why do any of this?
Well, my friend, the real power of pointers comes into play when you start passing them to functions. Why
is this a big deal? You might recall from before that you could pass all kinds of arguments to functions and
they’d be dutifully copied into parameters, and then you could manipulate local copies of those variables
from within the function, and then you could return a single value.
What if you wanted to bring back more than one single piece of data from the function? I mean, you can
only return one thing, right? What if I answered that question with another question? …Er, two questions?
What happens when you pass a pointer as an argument to a function? Does a copy of the pointer get put
into its corresponding parameter? You bet your sweet peas it does. Remember how earlier I rambled on
and on about how EVERY SINGLE ARGUMENT gets copied into parameters and the function uses a copy
of the argument? Well, the same is true here. The function will get a copy of the pointer.
But, and this is the clever part: we will have set up the pointer in advance to point at a variable… and
then the function can dereference its copy of the pointer to get back to the original variable! The function
can’t see the variable itself, but it can certainly dereference a pointer to that variable!
This is analogous to writing a home address on a piece of paper, and then copying that onto another piece
of paper. You now have two pointers to that house, and both are equally good at getting you to the house
itself.
In the case of a function call. one of the copies is stored in a pointer variable out in the calling scope, and
the other is stored in a pointer variable that is the parameter of the function.
Example! Let’s revisit our old increment() function, but this time let’s make it so that it actually incre-
ments the value out in the caller.
1 #include <stdio.h>
2
8 int main(void)
9 {
10 int i = 10;
11 int *j = &i; // note the address-of; turns it into a pointer to i
12
16 increment(j); // j is an int*--to i
17
Ok! There are a couple things to see here… not the least of which is that the increment() function takes
an int* as an argument. We pass it an int* in the call by changing the int variable i to an int* using
the address-of operator. (Remember, a pointer holds an address, so we make pointers to variables by
running them through the address-of operator.)
The increment() function gets a copy of the pointer. Both the original pointer j (in main()) and the
copy of that pointer p (the parameter in increment()) point to the same address, namely the one holding
the value i. (Again, by analogy, like two pieces of paper with the same home address written on them.)
Dereferencing either will allow you to modify the original variable i! The function can modify a variable
in another scope! Rock on!
The above example is often more concisely written in the call just by using address-of right in the argument
list:
printf("i is %d\n", i); // prints "10"
increment(&i);
34 Chapter 5. Pointers—Cower In Fear!
Pointer enthusiasts will recall from early on in the guide, we used a function to read from the keyboard,
scanf()… and, although you might not have recognized it at the time, we used the address-of to pass
a pointer to a value to scanf(). We had to pass a pointer, see, because scanf() reads from the keyboard
(typically) and stores the result in a variable. The only way it can see that variable out in the calling
function’s scope is if we pass a pointer to that variable:
int i = 0;
See, scanf() dereferences the pointer we pass it in order to modify the variable it points to. And now
you know why you have to put that pesky ampersand in there!
p = NULL;
Since it doesn’t point to a value, dereferencing it is undefined behavior, and probably will result in a crash:
int *p = NULL;
Despite being called the billion dollar mistake by its creator6 , the NULL pointer is a good sentinel value7
and general indicator that a pointer hasn’t yet been initialized.
(Of course, like other variables, the pointer points to garbage unless you explicitly assign it to point to an
address or NULL.)
Can we make that into one line? We can. But where does the * go?
The rule is that the * goes in front of any variable that is a pointer type. That is. the * is not part of the
int in this example. it’s a part of variable p.
It’s important to note that the following line does not declare two pointers:
int *p, q; // p is a pointer to an int; q is just an int.
This can be particularly insidious-looking if the programmer writes this following (valid) line of code
which is functionally identical to the one above.
int* p, q; // p is a pointer to an int; q is just an int.
So take a look at this and determine which variables are pointers and which are not:
int *a, b, c, *d, e, *f, g, h, *i;
You might see code in the wild with that last sizeof in there. Just remember that sizeof is all about the
type of the expression, not the variables in the expression themselves.
8
The pointer type variables are a, d, f, and i, because those are the ones with * in front of them.
36 Chapter 5. Pointers—Cower In Fear!
Chapter 6
Arrays
“Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought,
proper consideration.”
—Stan Kelly-Bootle, computer scientist
Luckily, C has arrays. I mean, I know it’s considered a low-level language1 but it does at least have the
concept of arrays built-in. And since a great many languages drew inspiration from C’s syntax, you’re
probably already familiar with using [ and ] for declaring and using arrays.
But C only barely has arrays! As we’ll find out later, arrays are just syntactic sugar in C—they’re actually
all pointers and stuff deep down. Freak out! But for now, let’s just use them as arrays. Phew.
3 int main(void)
4 {
5 int i;
6 float f[4]; // Declare an array of 4 floats
7
When you declare an array, you have to give it a size. And the size has to be fixed2 .
In the above example, we made an array of 4 floats. The value in the square brackets in the declaration
lets us know that.
Later on in subsequent lines, we access the values in the array, setting them or getting them, again with
square brackets.
1
These days, anyway.
2
Again, not really, but variable-length arrays—of which I’m not really a fan—are a story for another time.
37
38 Chapter 6. Arrays
If it’s an array of chars, then sizeof the array is the number of elements, since sizeof(char) is defined
to be 1. For anything else, you have to divide by the size of each element.
But this trick only works in the scope in which the array was defined. If you pass the array to a function,
it doesn’t work. Even if you make it “big” in the function signature:
void foo(int x[12])
{
printf("%zu\n", sizeof x); // 8?! What happened to 48?
printf("%zu\n", sizeof(int)); // 4 bytes per int
This is because when you “pass” arrays to functions, you’re only passing a pointer to the first element,
and that’s what sizeof measures. More on this in the Passing Single Dimensional Arrays to Functions
section, below.
One more thing you can do with sizeof and arrays is get the size of an array of a fixed number of elements
without declaring the array. This is like how you can get the size of an int with sizeof(int).
For example, to see how many bytes would be needed for an array of 48 doubles, you can do this:
sizeof(double [48]);
3 int main(void)
4 {
5 int i;
6 int a[5] = {22, 37, 3490, 18, 95}; // Initialize with these values
7
3
Since arrays are just pointers to the first element of the array under the hood, there’s no additional information recording the
length.
4
Because when you pass an array to a function, you’re actually just passing a pointer to the first element of that array, not the
“entire” array.
6.3. Array Initializers 39
9 printf("%d\n", a[i]);
10 }
11 }
Catch: initializer values must be constant terms. Can’t throw variables in there. Sorry, Illinois!
You should never have more items in your initializer than there is room for in the array, or the compiler
will get cranky:
foo.c: In function ‘main’:
foo.c:6:39: warning: excess elements in array initializer
6 | int a[5] = {22, 37, 3490, 18, 95, 999};
| ^~~
foo.c:6:39: note: (near initialization for ‘a’)
But (fun fact!) you can have fewer items in your initializer than there is room for in the array. The
remaining elements in the array will be automatically initialized with zero. This is true in general for all
types of array initializers: if you have an initializer, anything not explicitly set to a value will be set to
zero.
int a[5] = {22, 37, 3490};
It’s a common shortcut to see this in an initializer when you want to set an entire array to zero:
int a[100] = {0};
Which means, “Make the first element zero, and then automatically make the rest zero, as well.”
You can set specific array elements in the initializer, as well, by specifying an index for the value! When
you do this, C will happily keep initializing subsequent values for you until the initializer runs out, filling
everything else with 0.
To do this, put the index in square brackets with an = after, and then set the value.
Because we listed index 5 as the start for 55, the resulting data in the array is:
0 11 22 0 0 55 66 77 0 0
Lastly, you can also have C compute the size of the array from the initializer, just by leaving the size off:
int a[3] = {22, 37, 3490};
3 int main(void)
4 {
5 int i;
6 int a[5] = {22, 37, 3490, 18, 95};
7
8 for (i = 0; i < 10; i++) { // BAD NEWS: printing too many elements!
9 printf("%d\n", a[i]);
10 }
11 }
Yikes! What’s that? Well, turns out printing off the end of an array results in what C developers call
undefined behavior. We’ll talk more about this beast later, but for now it means, “You’ve done something
bad, and anything could happen during your program run.”
And by anything, I mean typically things like finding zeroes, finding garbage numbers, or crashing. But
really the C spec says in this circumstance the compiler is allowed to emit code that does anything5 .
Short version: don’t do anything that causes undefined behavior. Ever6 .
These are stored in memory in row-major order7 . This means with a 2D array, the first index listed
indicates the row, and the second the column.
You can also use initializers on multidimensional arrays by nesting them:
1 #include <stdio.h>
2
5
In the good old MS-DOS days before memory protection was a thing, I was writing some particularly abusive C code that
deliberately engaged in all kinds of undefined behavior. But I knew what I was doing, and things were working pretty well. Until I
made a misstep that caused a lockup and, as I found upon reboot, nuked all my BIOS settings. That was fun. (Shout-out to @man
for those fun times.)
6
There are a lot of things that cause undefined behavior, not just out-of-bounds array accesses. This is what makes the C language
so exciting.
7
https://en.wikipedia.org/wiki/Row-_and_column-major_order
6.6. Arrays and Pointers 41
3 int main(void)
4 {
5 int row, col;
6
3 int main(void)
8
This is technically incorrect, as a pointer to an array and a pointer to the first element of an array have different types. But we
can burn that bridge when we get to it.
42 Chapter 6. Arrays
4 {
5 int a[5] = {11, 22, 33, 44, 55};
6 int *p;
7
Just referring to the array name in isolation is the same as getting a pointer to the first element of the array!
We’re going to use this extensively in the upcoming examples.
But hold on a second—isn’t p an int*? And *p gives us 11, same as a[0]? Yessss. You’re starting to
get a glimpse of how arrays and pointers are related in C.
24 int main(void)
25 {
26 int x[5] = {11, 22, 33, 44, 55};
27
28 times2(x, 5);
29 times3(x, 5);
6.6. Arrays and Pointers 43
30 times4(x, 5);
31 }
All those methods of listing the array as a parameter in the function are identical.
void times2(int *a, int len)
void times3(int a[], int len)
void times4(int a[5], int len)
14 int main(void)
15 {
16 int x[5] = {1, 2, 3, 4, 5};
17
18 double_array(x, 5);
19
Even though we passed the array in as parameter a which is type int*, look at how we access it using
array notation with a[i]! Whaaaat. This is totally allowed.
Later when we talk about the equivalence between arrays and pointers, we’ll see how this makes a lot
more sense. For now, it’s enough to know that functions can make changes to arrays that are visible out
in the caller.
9
C11 §6.7.6.2¶1 requires it be greater than zero. But you might see code out there with arrays declared of zero length at the
end of structs and GCC is particularly lenient about it unless you compile with -pedantic. This zero-length array was a hackish
mechanism for making variable-length structures. Unfortunately, it’s technically undefined behavior to access such an array even
though it basically worked everywhere. C99 codified a well-defined replacement for it called flexible array members, which we’ll
chat about later.
44 Chapter 6. Arrays
12 int main(void)
13 {
14 int x[2][3] = {
15 {1, 2, 3},
16 {4, 5, 6}
17 };
18
19 print_2D_array(x);
20 }
The compiler really only needs the second dimension so it can figure out how far in memory to skip for
each increment of the first dimension. In general, it needs to know all the dimensions except the first one.
Also, remember that the compiler does minimal compile-time bounds checking (if you’re lucky), and C
does zero runtime checking of bounds. No seat belts! Don’t crash by accessing array elements out of
bounds!
10
This is also equivalent: void print_2D_array(int (*a)[3]), but that’s more than I want to get into right now.
Chapter 7
Strings
The first one has a newline at the end—quite a common thing to see.
The last one has quotes embedded within it, but you see each is preceded by (we say “escaped by”) a
backslash (\) indicating that a literal quote belongs in the string at this point. This is how the C compiler
can tell the difference between printing a double quote and the double quote at the end of the string.
Check out that type: pointer to a char. The string variable s is actually a pointer to the first character in
that string, namely the H.
And we can print it with the %s (for “string”) format specifier:
char *s = "Hello, world!";
45
46 Chapter 7. Strings
This means you can use array notation to access characters in a string. Let’s do exactly that to print all the
characters in a string on the same line:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char s[] = "Hello, world!";
6
Note that we’re using the format specifier %c to print a single character.
Also, check this out. The program will still work fine if we change the definition of s to be a char* type:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char *s = "Hello, world!"; // char* here
6
And we still can use array notation to get the job done when printing it out! This is surprising, but is still
only because we haven’t talked about array/pointer equivalence yet. But this is yet another hint that arrays
and pointers are the same thing, deep down.
This one is a pointer to a string literal (i.e. a pointer to the first character in a string):
char *s = "Hello, world!";
The behavior is undefined. Probably, depending on your system, a crash will result.
But declaring it as an array is different. This one is a mutable copy of the string that we can change at
will:
7.5. Getting String Length 47
So remember: if you have a pointer to a string literal, don’t try to change it! And if you use a string in
double quotes to initialize an array, that’s not actually a string literal.
4 int main(void)
5 {
6 char *s = "Hello, world!";
7
The strlen() function returns type size_t, which is an integer type so you can use it for integer math.
We print size_t with %zu.
The above program prints:
The string is 13 bytes long.
When you include a string in double quotes in your code, the NUL character is automatically, implicitly
included.
char *s = "Hello!"; // Actually "Hello!\0" behind the scenes
So with this in mind, let’s write our own strlen() function that counts chars in a string until it finds a
NUL.
The procedure is to look down the string for a single NUL character, counting as we go4 :
int my_strlen(char *s)
{
int count = 0;
return count;
}
And that’s basically how the built-in strlen() gets the job done.
3 int main(void)
4 {
5 char s[] = "Hello, world!";
6 char *t;
7
11 // We modify t
12 t[0] = 'z';
13
If you want to make a copy of a string, you have to copy it a byte at a time—but this is made easier with
the strcpy() function5 .
Before you copy the string, make sure you have room to copy it into, i.e. the destination array that’s going
to hold the characters needs to be at least as long as the string you’re copying.
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char s[] = "Hello, world!";
7 char t[100]; // Each char is one byte, so plenty of room
4
Later we’ll learn a neater way to do it with pointer arithmetic.
5
There’s a safer function called strncpy() that you should probably use instead, but we’ll get to that later.
7.7. Copying a String 49
12 // We modify t
13 t[0] = 'z';
14
Notice with strcpy(), the destination pointer is the first argument, and the source pointer is the second.
A mnemonic I use to remember this is that it’s the order you would have put t and s if an assignment =
worked for strings, with the source on the right and the destination on the left.
50 Chapter 7. Strings
Chapter 8
Structs
In C, we have something called a struct, which is a user-definable type that holds multiple pieces of
data, potentially of different types.
It’s a convenient way to bundle multiple variables into a single one. This can be beneficial for passing
variables to functions (so you just have to pass one instead of many), and useful for organizing data and
making code more readable.
If you’ve come from another language, you might be familiar with the idea of classes and objects. These
don’t exist in C, natively1 . You can think of a struct as a class with only data members, and no methods.
This is often done at the global scope outside any functions so that the struct is globally available.
When you do this, you’re making a new type. The full type name is struct car. (Not just car—that
won’t work.)
There aren’t any variables of that type yet, but we can declare some:
struct car saturn; // Variable "saturn" of type "struct car"
1
Although in C individual items in memory like ints are referred to as “objects”, they’re not objects in an object-oriented
programming sense.
2
The Saturn was a popular brand of economy car in the United States until it was put out of business by the 2008 crash, sadly so
to us fans.
51
52 Chapter 8. Structs
There on the first lines, we set the values in the struct car, and then in the next bit, we print those
values out.
You can do it with an initializer by putting values in for the fields in the order they appear in the struct
when you define the variable. (This won’t work after the variable has been defined—it has to happen in
the definition).
struct car {
char *name;
float price;
int speed;
};
The fact that the fields in the initializer need to be in the same order is a little freaky. If someone changes
the order in struct car, it could break all the other code!
We can be more specific with our initializers:
struct car saturn = {.speed=175, .name="Saturn SL/2"};
Now it’s independent of the order in the struct declaration. Which is safer code, for sure.
Similar to array initializers, any missing field designators are initialized to zero (in this case, that would
be .price, which I’ve omitted).
Let’s try passing in a pointer, making a function that will allow you to set the .price field of the struct
car:
1 #include <stdio.h>
2
3 struct car {
4 char *name;
5 float price;
6 int speed;
7 };
8
9 int main(void)
10 {
11 struct car saturn = {.speed=175, .name="Saturn SL/2"};
12
You should be able to come up with the function signature for set_price() just by looking at the types
of the arguments we have there.
saturn is a struct car, so &saturn must be the address of the struct car, AKA a pointer to a struct
car, namely a struct car*.
That won’t work because the dot operator only works on structs… it doesn’t work on pointers to
structs.
Ok, so we can dereference the struct to de-pointer it to get to the struct itself. Dereferencing a struct
car* results in the struct car that the pointer points to, which we should be able to use the dot operator
on:
void set_price(struct car *c, float new_price) {
(*c).price = new_price; // Works, but is ugly and non-idiomatic :(
}
And that works! But it’s a little clunky to type all those parens and the asterisk. C has some syntactic
sugar called the arrow operator that helps with that.
So when accessing fields, when do we use dot and when do we use arrow?
• If you have a struct, use dot (.).
• If you have a pointer to a struct, use arrow (->).
And returning a struct (as opposed to a pointer to one) from a function also makes a similar copy to the
receiving variable.
This is not a “deep copy”4 . All fields are copied as-is, including pointers to things.
4
A deep copy follows pointer in the struct and copies the data they point to, as well. A shallow copy just copies the pointers,
but not the things they point to. C doesn’t come with any built-in deep copy functionality.
5
https://stackoverflow.com/questions/141720/how-do-you-compare-structs-for-equality-in-c
Chapter 9
File Input/Output
We’ve already seen a couple examples of I/O with scanf() and printf() for doing I/O at the console
(screen/keyboard).
But we’ll push those concepts a little farther this chapter.
We’ve actually been using these implicitly already, it turns out. For example, these two calls are the same:
printf("Hello, world!\n");
fprintf(stdout, "Hello, world!\n"); // printf to a file
For this reason, you should send serious error messages to stderr instead of stdout.
More on how to do that later.
55
56 Chapter 9. File Input/Output
And let’s write a program to open the file, read a character out of it, and then close the file when we’re
done. That’s the game plan!
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp; // Variable to represent open file
6
See how when we opened the file with fopen(), it returned the FILE* to us so we could use it later.
(I’m leaving it out for brevity, but fopen() will return NULL if something goes wrong, like file-not-found,
so you should really error check it!)
Also notice the "r" that we passed in—this means “open a text stream for reading”. (There are various
strings we can pass to fopen() with additional meaning, like writing, or appending, and so on.)
After that, we used the fgetc() function to get a character from the stream. You might be wondering
why I’ve made c an int instead of a char—hold that thought!
Finally, we close the stream when we’re done with it. All streams are automatically closed when the
program exits, but it’s good form and good housekeeping to explicitly close any files yourself when done
with them.
The FILE* keeps track of our position in the file. So subsequent calls to fgetc() would get the next
character in the file, and then the next, until the end.
But that sounds like a pain. Let’s see if we can make it easier.
can hold more values. so int it is. But unless you’re comparing the returned value against EOF, you can
know, deep down, it’s a char.
All right! Back to reality! We can use this to read the whole file in a loop.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 int c;
7
8 fp = fopen("hello.txt", "r");
9
13 fclose(fp);
14 }
(If line 10 is too weird, just break it down starting with the innermost-nested parens. The first thing we
do is assign the result of fgetc() into c, and then we compare that against EOF. We’ve just crammed it
into a single line. This might look hard to read, but study it—it’s idiomatic C.)
And running this, we see:
Hello, world!
But still, we’re operating a character at a time, and lots of text files make more sense at the line level.
Let’s switch to that.
And here’s some code that reads that file a line at a time and prints out a line number before each one:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 char s[1024]; // Big enough for any line this program will encounter
7 int linecount = 0;
8
9 fp = fopen("quote.txt", "r");
10
2
If the buffer’s not big enough to read in an entire line, it’ll just stop reading mid-line, and the next call to fgets() will continue
reading the rest of the line.
58 Chapter 9. File Input/Output
14 fclose(fp);
15 }
Yes, we could read these with fgets() and then parse the string with sscanf() (and in some ways that’s
more resilient against corrupted files), but in this case, let’s just use fscanf() and pull it in directly.
The fscanf() function skips leading whitespace when reading, and returns EOF on end-of-file or error.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 char name[1024]; // Big enough for any line this program will encounter
7 float length;
8 int mass;
9
10 fp = fopen("whales.txt", "r");
11
15 fclose(fp);
16 }
To do so, we have to fopen() the file in write mode by passing "w" as the second argument. Opening an
existing file in "w" mode will instantly truncate that file to 0 bytes for a full overwrite.
We’ll put together a simple program that outputs a file output.txt using a variety of output functions.
9.6. Binary File I/O 59
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 int x = 32;
7
8 fp = fopen("output.txt", "w");
9
10 fputc('B', fp);
11 fputc('\n', fp); // newline
12 fprintf(fp, "x = %d\n", x);
13 fputs("Hello, world!\n", fp);
14
15 fclose(fp);
16 }
Fun fact: since stdout is a file, you could replace line 8 with:
fp = stdout;
and the program would have outputted to the console instead of to a file. Try it!
3 int main(void)
4 {
5 FILE *fp;
6 unsigned char bytes[6] = {5, 37, 0, 88, 255, 12};
7
3
Normally the second program would read all the bytes at once, and then print them out in a loop. That would be more efficient.
But we’re going for demo value, here.
60 Chapter 9. File Input/Output
11 //
12 // * Pointer to data to write
13 // * Size of each "piece" of data
14 // * Count of each "piece" of data
15 // * FILE*
16
19 fclose(fp);
20 }
Those two middle arguments to fwrite() are pretty odd. But basically what we want to tell the function
is, “We have items that are this big, and we want to write that many of them.” This makes it convenient
if you have a record of a fixed length, and you have a bunch of them in an array. You can just tell it the
size of one record and how many to write.
In the example above, we tell it each record is the size of a char, and we have 6 of them.
Running the program gives us a file output.bin, but opening it in a text editor doesn’t show anything
friendly! It’s binary data—not text. And random binary data I just made up, at that!
If I run it through a hex dump4 program, we can see the output as bytes:
05 25 00 58 ff 0c
And those values in hex do match up to the values (in decimal) that we wrote out.
But now let’s try to read them back in with a different program. This one will open the file for binary
reading ("rb" mode) and will read the bytes one at a time in a loop.
fread() has the neat feature where it returns the number of bytes read, or 0 on EOF. So we can loop until
we see that, printing numbers as we go.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 unsigned char c;
7
Woo hoo!
What I’m getting at is this: it’s not portable to just fwrite() an entire struct out to a file when you
don’t know where the padding will end up.
How do we fix this? Hold that thought—we’ll look at some ways to do this after looking at another related
problem.
Numbers!
Turns out all architectures don’t represent numbers in memory the same way.
Let’s look at a simple fwrite() of a 2-byte number. We’ll write it in hex so each byte is clear. The most
significant byte will have the value 0x12 and the least significant will have the value 0x34.
unsigned short v = 0x1234; // Two bytes, 0x12 and 0x34
5
https://en.wikipedia.org/wiki/Endianess
6
And this is why I used individual bytes in my fwrite() and fread() examples, above, shrewdly.
7
https://en.wikipedia.org/wiki/Protocol_buffers
62 Chapter 9. File Input/Output
Chapter 10
Well, not so much making new types as getting new names for existing types. Sounds kinda pointless on
the surface, but we can really use this to make our code cleaner.
You can take any existing type and do it. You can even make a number of types with a comma list:
typedef int antelope, bagel, mushroom; // These are all "int"
That’s really useful, right? That you can type mushroom instead of int? You must be super excited about
this feature!
OK, Professor Sarcasm—we’ll get to some more common applications of this in a moment.
10.1.1 Scoping
typedef follows regular scoping rules.
For this reason, it’s quite common to find typedef at file scope (“global”) so that all functions can use
the new types at will.
63
64 Chapter 10. typedef: Making New Types
Personally, I don’t care for this practice. I like the clarity the code has when you add the word struct to
the type; programmers know what they’re getting. But it’s really common so I’m including it here.
Now I want to run the exact same example in a way that you might commonly see. We’re going to put
the struct animal in the typedef. You can mash it all together like this:
// original name
// |
// v
// |-----------|
typedef struct animal {
char *name;
int leg_count, speed;
} animal; // <-- new name
That’s exactly the same as the previous example, just more concise.
But that’s not all! There’s another common shortcut that you might see in code using what are called
anonymous structures1 . It turns out you don’t actually need to name the structure in a variety of places,
and with typedef is one of them.
1
We’ll talk more about these later.
10.2. typedef in Practice 65
// and
Then if later you want to change to another type, like long double, you just need to change the typedef:
// voila!
// |---------|
typedef long double app_float;
app_float f1, f2, f3; // Now these are all long doubles
int a = 10;
intptr x = &a; // "intptr" is type "int*"
I really don’t like this practice. It hides the fact that x is a pointer type because you don’t see a * in the
declaration.
IMHO, it’s better to explicitly show that you’re declaring a pointer type so that other devs can clearly see
it and don’t mistake x for having a non-pointer type.
But at last count, say, 832,007 people had a different opinion.
typedef struct {
int x, y;
} MyPoint; // CamelCase
typedef struct {
int x, y;
} Mypoint; // Leading uppercase
typedef struct {
int x, y;
} MY_POINT; // UPPER SNAKE CASE
66 Chapter 10. typedef: Making New Types
The C11 specification doesn’t dictate one way or another, and shows examples in all uppercase and all
lowercase.
K&R2 uses leading uppercase predominantly, but show some examples in uppercase and snake case (with
_t).
If you have a style guide in use, stick with it. If you don’t, grab one and stick with it.
I don’t like it because it hides the array nature of the variable, but it’s possible to do.
Chapter 11
Time to get more into it with a number of new pointer topics! If you’re not up to speed with pointers,
check out the first section in the guide on the matter.
Now let’s use pointer arithmetic to print the next element in the array, the one at index 1:
printf("%d\n", *(p + 1)); // Prints 22!!
What happened there? C knows that p is a pointer to an int. So it knows the sizeof an int1 and it
knows to skip that many bytes to get to the next int after the first one!
In fact, the prior example could be written these two equivalent ways:
printf("%d\n", *p); // Prints 11
printf("%d\n", *(p + 0)); // Prints 11
1
Recall that the sizeof operator tells you the size in bytes of an object in memory.
67
68 Chapter 11. Pointers II: Arithmetic
And that works the same as if we used array notation! Oooo! Getting closer to that array/pointer equiva-
lence thing! More on this later in this chapter.
But what’s actually happening, here? How does it work?
Remember from early on that memory is like a big array, where a byte is stored at each array index?
And the array index into memory has a few names:
• Index into memory
• Location
• Address
• Pointer!
So a point is an index into memory, somewhere.
For a random example, say that a number 3490 was stored at address (“index”) 23,237,489,202. If we
have an int pointer to that 3490, that value of that pointer is 23,237,489,202… because the pointer is the
memory address. Different words for the same thing.
And now let’s say we have another number, 4096, stored right after the 3490 at address 23,237,489,210
(8 higher than the 3490 because each int in this example is 8 bytes long).
If we add 1 to that pointer, it actually jumps ahead sizeof(int) bytes to the next int. It knows to jump
that far ahead because it’s an int pointer. If it were a float pointer, it’d jump sizeof(float) bytes
ahead to get to the next float!
So you can look at the next int, by adding 1 to the pointer, the one after that by adding 2 to the pointer,
and so on.
And we also have p pointing to the element at index 0 of a, namely 11, just like before.
Now—let’s start incrementing p so that it points at subsequent elements of the array. We’ll do this until p
points to the 999; that is, we’ll do it until *p == 999:
while (*p != 999) { // While the thing p points to isn't 999
printf("%d\n", *p); // Print it
p++; // Move p to point to the next int!
}
When we give it a run, first p points to 11. Then we increment p, and it points to 22, and then again, it
points to 33. And so on, until it points to 999 and we quit.
16 int main(void)
17 {
18 printf("%d\n", my_strlen("Hello, world!")); // Prints "13"
19 }
Remember that you can only use pointer subtraction between two pointers that point to the same array!
but that’s a little harder to grok. Just make sure you include parentheses if the expressions are complicated
so all your math happens in the right order.
2
Or string, which is really an array of chars. Somewhat peculiarly, you can also have a pointer that references one past the end
of the array without a problem and still do math on it. You just can’t dereference it when it’s out there.
70 Chapter 11. Pointers II: Arithmetic
This means we can decide if we’re going to use array or pointer notation for any array or pointer (assuming
it points to an element of an array).
Let’s use an array and pointer with both array and pointer notation:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int a[] = {11, 22, 33, 44, 55};
6
So you can see that in general, if you have an array variable, you can use pointer or array notion to access
elements. Same with a pointer variable.
The one big difference is that you can modify a pointer to point to a different address, but you can’t do
that with an array variable.
this means you can pass either an array or a pointer to this function and have it work!
char s[] = "Antelopes";
char *t = "Wombats";
And it’s also why these two function signatures are equivalent:
int my_strlen(char *s) // Works!
int my_strlen(char s[]) // Works, too!
11.3. void Pointers 71
This function copies n bytes of memory starting from address s1 into the memory starting at address s2.
But look! s1 and s2 are void*s! Why? What does it mean? Let’s run more examples to see.
For instance, we could copy a string with memcpy() (though strcpy() is more appropriate for strings):
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char s[] = "Goats!";
7 char t[100];
8
4 int main(void)
5 {
6 int a[] = {11, 22, 33};
7 int b[3];
8
11 printf("%d\n", b[1]); // 22
12 }
That one’s a little wild—you see what we did there with memcpy()? We copied the data from a to b, but
we had to specify how many bytes to copy, and an int is more than one byte.
OK, then—how many bytes does an int take? Answer: depends on the system. But we can tell how
many bytes any type takes with the sizeof operator.
So there’s the answer: an int takes sizeof(int) bytes of memory to store.
72 Chapter 11. Pointers II: Arithmetic
And if we have 3 of them in our array, like we did in that example, the entire space used for the 3 ints
must be 3 * sizeof(int).
(In the string example, earlier, it would have been more technically accurate to copy 7 * sizeof(char)
bytes. But chars are always one byte large, by definition, so that just devolves into 7 * 1.)
We could even copy a float or a struct with memcpy()! (Though this is abusive—we should just use
= for that):
struct antelope my_antelope;
struct antelopy my_clone_antelope;
// ...
Look at how versatile memcpy() is! If you have a pointer to a source and a pointer to a destination, and
you have the number of bytes you want to copy, you can copy any type of data.
Imagine if we didn’t have void*. We’d have to write specialized memcpy() functions for each type:
memcpy_int(int *a, int *b, int count);
memcpy_float(float *a, float *b, int count);
memcpy_double(double *a, double *b, int count);
memcpy_char(char *a, char *b, int count);
memcpy_unsigned_char(unsigned char *a, unsigned char *b, int count);
// etc... blech!
Much better to just use void* and have one function that can do it all.
That’s the power of void*. You can write functions that don’t care about the type and is still able to do
things with it.
But with great power comes great responsibility. Maybe not that great in this case, but there are some
limits.
1. You cannot do pointer arithmetic on a void*. 2. You cannot dereference a void*. 3. You cannot use
the arrow operator on a void*, since it’s also a dereference. 4. You cannot use array notation on a void*,
since it’s also a dereference, as well3 .
And if you think about it, these rules make sense. All those operations rely on knowing the sizeof the
type of data pointed to, and with void*, we don’t know the size of the data being pointed to—it could be
anything!
But wait—if you can’t dereference a void* what good can it ever do you?
Like with memcpy(), it helps you write generic functions that can handle multiple types of data. But the
secret is that, deep down, you convert the void* to another type before you use it!
And conversion is easy: you can just assign into a variable of the desired type4 .
char a = 'X'; // A single char
Let’s write our own memcpy() to try this out. We can copy bytes (chars), and we know the number of
bytes because it’s passed in.
3
Because remember that array notation is just a dereference and some pointer math, and you can’t dereference a void*!
4
You can also cast the void* to another type, but we haven’t gotten to casts yet.
11.3. void Pointers 73
Right there at the beginning, we copy the void*s into char*s so that we can use them as char*s. It’s as
easy as that.
Then some fun in a while loop, where we decrement byte_count until it becomes false (0). Remember
that with post-decrement, the value of the expression is computed (for while to use) and then the variable
is decremented.
And some fun in the copy, where we assign *d = *s to copy the byte, but we do it with post-increment
so that both d and s move to the next byte after the assignment is made.
Lastly, most memory and string functions return a copy of a pointer to the destination string just in case
the caller wants to use it.
Now that we’ve done that, I just want to quickly point out that we can use this technique to iterate over
the bytes of any object in C, floats, structs, or anything!
Let’s run one more real-world example with the built-in qsort() routine that can sort anything thanks to
the magic of void*s.
(In the following example, you can ignore the word const, which we haven’t covered yet.)
1 #include <stdio.h>
2 #include <stdlib.h>
3
26
30 return 0;
31 }
32
33 int main(void)
34 {
35 // Let's build an array of 4 struct animals with different
36 // characteristics. This array is out of order by leg_count, but
37 // we'll sort it in a second.
38 struct animal a[4] = {
39 {.name="Dog", .leg_count=4},
40 {.name="Monkey", .leg_count=2},
41 {.name="Antelope", .leg_count=4},
42 {.name="Snake", .leg_count=0}
43 };
44
As long as you give qsort() a function that can compare two items that you have in your array to be
sorted, it can sort anything. And it does this without needing to have the types of the items hardcoded in
there anywhere. qsort() just rearranges blocks of bytes based on the results of the compar() function
you passed in.
Chapter 12
This is one of the big areas where C likely diverges from languages you already know: manual memory
management.
Other languages uses reference counting, garbage collection, or other means to determine when to allocate
new memory for some data—and when to deallocate it when no variables refer to it.
And that’s nice. It’s nice to be able to not worry about it, to just drop all the references to an item and trust
that at some point the memory associated with it will be freed.
But C’s not like that, entirely.
Of course, in C, some variables are automatically allocated and deallocated when they come into scope
and leave scope. We call these automatic variables. They’re your average run-of-the-mill block scope
“local” variables. No problem.
But what if you want something to persist longer than a particular block? This is where manual memory
management comes into play.
You can tell C explicitly to allocate for you a certain number of bytes that you can use as you please. And
these bytes will remain allocated until you explicitly free that memory1 .
It’s important to free the memory you’re done with! If you don’t, we call that a memory leak and your
process will continue to reserve that memory until it exits.
If you manually allocated it, you have to manually free it when you’re done with it.
So how do we do this? We’re going to learn a couple new functions, and make use of the sizeof operator
to help us learn how many bytes to allocate.
In common C parlance, devs say that automatic local variables are allocated “on the stack”, and manually-
allocated memory is “on the heap”. The spec doesn’t talk about either of those things, but all C devs will
know what you’re talking about if you bring them up.
All functions we’re going to learn in this chapter can be found in <stdlib.h>.
75
76 Chapter 12. Manual Memory Allocation
So… how many bytes should I allocate? We can use sizeof to help with that. If we want to allocate
enough room for a single int, we can use sizeof(int) and pass that to malloc().
After we’re done with some allocated memory, we can call free() to indicate we’re done with that
memory and it can be used for something else. As an argument, you pass the same pointer you got from
malloc() (or a copy of it). It’s undefined behavior to use a memory region after you free() it.
Let’s try. We’ll allocate enough memory for an int, and then store something there, and the print it.
// Allocate space for a single int (sizeof(int) bytes-worth):
int *p = malloc(sizeof(int));
Now, in that contrived example, there’s really no benefit to it. We could have just used an automatic int
and it would have worked. But we’ll see how the ability to allocate memory this way has its advantages,
especially with more complex data structures.
One more thing you’ll commonly see takes advantage of the fact that sizeof can give you the size of
the result type of any constant expression. So you could put a variable name in there, too, and use that.
Here’s an example of that, just like the previous one:
int *p = malloc(sizeof *p); // *p is an int, so same as sizeof(int)
x = malloc(sizeof(int) * 10);
if (x == NULL) {
printf("Error allocating 10 ints\n");
// do something here to handle it
}
Here’s a common pattern that you’ll see, where we do the assignment and the condition on the same line:
int *x;
We can allocate a contiguous stretch of memory—we’ve seen how to do that. If we wanted 3490 bytes of
memory, we could just ask for it:
char *p = malloc(3490); // Voila
And—indeed!—that’s an array of 3490 chars (AKA a string!) since each char is 1 byte. In other words,
sizeof(char) is 1.
Note: there’s no initialization done on the newly-allocated memory—it’s full of garbage. Clear it with
memset() if you want to, or see calloc(), below.
But we can just multiply the size of the thing we want by the number of elements we want, and then access
them using either pointer or array notation. Example!
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 // Allocate space for 10 ints
7 int *p = malloc(sizeof(int) * 10);
8
The key’s in that malloc() line. If we know each int takes sizeof(int) bytes to hold it, and we know
we want 10 of them, we can just allocate exactly that many bytes with:
sizeof(int) * 10
And this trick works for every type. Just pass it to sizeof and multiply by the size of the array.
• Instead of a single argument, you pass the size of one element, and the number of elements you
wish to allocate. It’s like it’s made for allocating arrays.
• It clears the memory to zero.
Again, the result is the same for both except malloc() doesn’t zero the memory by default.
78 Chapter 12. Manual Memory Allocation
Let’s allocate an array of 20 floats, and then change our mind and make it an array of 40.
We’re going to assign the return value of realloc() into another pointer just to make sure it’s not NULL.
If it’s not, then we can reassign it into our original pointer. (If we just assigned the return value directly
into the original pointer, we’d lose that pointer if the function returned NULL and we’d have no way to get
it back.)
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 // Allocate space for 20 floats
7 float *p = malloc(sizeof *p * 20); // sizeof *p same as sizeof(float)
8
32
Notice in there how we took the return value from realloc() and reassigned it into the same pointer
variable p that we passed in. That’s pretty common to do.
Also if line 7 is looking weird, with that sizeof *p in there, remember that sizeof works on the size of
the type of the expression. And the type of *p is float, so that line is equivalent to sizeof(float).
36 if (new_buf == NULL) {
37 free(buf); // On error, free and bail
38 return NULL;
80 Chapter 12. Manual Memory Allocation
39 }
40
56 // Shrink to fit
57 if (offset < bufsize - 1) { // If we're short of the end
58 char *new_buf = realloc(buf, offset + 1); // +1 for NUL terminator
59
69 return buf;
70 }
71
72 int main(void)
73 {
74 FILE *fp = fopen("foo.txt", "r");
75
76 char *line;
77
83 fclose(fp);
84 }
When growing memory like this, it’s common (though hardly a law) to double the space needed each step
just to minimize the number of realloc()s that occur.
Finally you might note that readline() returns a pointer to a malloc()d buffer. As such, it’s up to the
caller to explicitly free() that memory when it’s done with it.
That could be convenient if you have some kind of allocation loop and you don’t want to special-case the
first malloc().
int *p = NULL;
int length = 0;
while (!done) {
// Allocate 10 more ints:
length += 10;
p = realloc(p, sizeof *p * length);
// Do amazing things
// ...
}
In that example, we didn’t need an initial malloc() since p was NULL to start.
The other restriction is that the number of bytes you allocate needs to be a multiple of the alignment. But
this might be changing. See C Defect Report 4602
Let’s do an example, allocating on a 64-byte boundary:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int main(void)
6 {
7 // Allocate 256 bytes aligned on a 64-byte boundary
8 char *p = aligned_alloc(64, 256); // 256 == 64 * 4
9
2
http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_460
82 Chapter 12. Manual Memory Allocation
I want to throw a note here about realloc() and aligned_alloc(). realloc() doesn’t have any
alignment guarantees, so if you need to get some aligned reallocated space, you’ll have to do it the hard
way with memcpy().
Here’s a non-standard aligned_realloc() function, if you need it:
void *aligned_realloc(void *ptr, size_t old_size, size_t alignment, size_t size)
{
char *new_ptr = aligned_alloc(alignment, size);
if (new_ptr == NULL)
return NULL;
if (ptr != NULL)
memcpy(new_ptr, ptr, copy_size);
free(ptr);
return new_ptr;
}
Note that it always copies data, taking time, while real realloc() will avoid that if it can. So this is
hardly efficient. Avoid needing to reallocate custom-aligned data.
Chapter 13
Scope
3 int main(void)
4 {
5 int a = 12; // Local to outer block, but visible in inner block
6
7 if (a == 12) {
8 int b = 99; // Local to inner block, not visible in outer block
9
1
https://en.wikipedia.org/wiki/Bit_bucket
83
84 Chapter 13. Scope
3 int main(void)
4 {
5 int i = 0;
6
11 int j = 5;
12
Historically, C required all the variables be defined before any code in the block, but this is no longer the
case in the C99 standard.
3 int main(void)
4 {
5 int i = 10;
6
7 {
8 int i = 20;
9
You might have noticed in that example that I just threw a block in there at line 7, not so much as a for or
if statement to kick it off! This is perfectly legal. Sometimes a dev will want to group a bunch of local
variables together for a quick computation and will do this, but it’s rare to see.
3 int shared = 10; // File scope! Visible to the whole file after this!
4
5 void func1(void)
6 {
7 shared += 100; // Now shared holds 110
8 }
9
13.3. for-loop Scope 85
10 void func2(void)
11 {
12 printf("%d\n", shared); // Prints "110"
13 }
14
15 int main(void)
16 {
17 func1();
18 func2();
19 }
Note that if shared were declared at the bottom of the file, it wouldn’t compile. It has to be declared
before any functions use it.
There are ways to further modify items at file scope, namely with static and extern, but we’ll talk more
about those later.
In that example, i’s lifetime begins the moment it is defined, and continues for the duration of the loop.
If the loop body is enclosed in a block, the variables defined in the for-loop are visible from that inner
scope.
Unless, of course, that inner scope hides them. This crazy example prints 999 five times:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 for (int i = 0; i < 5; i++) {
6 int i = 999; // Hides the i in the for-loop scope
7 printf("%d\n", i);
8 }
9 }
We’re used to char, int, and float types, but it’s now time to take that stuff to the next level and see
what else we have out there in the types department!
Why? Why would you decide you only wanted to hold positive numbers?
Answer: you can get larger numbers in an unsigned variable than you can in a signed ones.
But why is that?
You can think of integers being represented by a certain number of bits1 . On my computer, an int is
represented by 64 bits.
And each permutation of bits that are either 1 or 0 represents a number. We can decide how to divvy up
these numbers.
With signed numbers, we use (roughly) half the permutations to represent negative numbers, and the other
half to represent positive numbers.
With unsigned, we use all the permutations to represent positive numbers.
On my computer with 64-bit ints using two’s complement2 to represent unsigned numbers, I have the
following limits on integer range:
Notice that the largest positive unsigned int is approximately twice as large as the largest positive int.
So you can get some flexibility there.
1
“Bit” is short for binary digit. Binary is just another way of representing numbers. Instead of digits 0-9 like we’re used to, it’s
digits 0-1.
2
https://en.wikipedia.org/wiki/Two%27s_complement
87
88 Chapter 14. Types II: Way More Types!
Deep down, char is just a small int, namely an integer that uses just a single byte of space, limiting its
range to…
Here the C spec gets just a little funky. It assures us that a char is a single byte, i.e. sizeof(char) ==
1. But then in C11 §3.6¶3 it goes out of its way to say:
OK, now, finally, we can figure out the range of numbers if we assume that a char is 8 bits and your
system uses the virtually universal two’s complement representation for signed and unsigned4 .
So, assuming those constraints, we can finally figure our ranges:
3 int main(void)
4 {
3
The industry term for a sequence of exactly, indisputably 8 bits is an octet.
In general, f you have an 𝑛 bit two’s complement number, the signed range is −2𝑛−1 to 2𝑛−1 − 1. And the unsigned range
4
is 0 to 2𝑛 − 1.
14.3. More Integer Types: short, long, long long 89
What about those constant characters in single quotes, like 'B'? How does that have a numeric value?
The spec is also hand-wavey here, since C isn’t designed to run on a single type of underlying system.
But let’s just assume for the moment that your character set is based on ASCII5 for at least the first 128
characters. In that case, the character constant will be converted to a char whose value is the same as the
ASCII value of the character.
That was a mouthful. Let’s just have an example:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char a = 10;
6 char b = 'B'; // ASCII value 66
7
This depends on your execution environment and the character set used6 . One of the most popular charac-
ter sets today is Unicode7 (which is a superset of ASCII), so for your basic 0-9, A-Z, a-z and punctuation,
you’ll almost certainly get the ASCII values out of them.
Let’s take a look at the integer data types and sizes in ascending order, grouped by signedness.
5
https://en.wikipedia.org/wiki/ASCII
6
https://en.wikipedia.org/wiki/List_of_information_system_character_sets
7
https://en.wikipedia.org/wiki/Unicode
90 Chapter 14. Types II: Way More Types!
There is no long long long type. You can’t just keep adding longs like that. Don’t be silly.
Two’s complement fans might have noticed something funny about those numbers. Why
does, for example, the signed char stop at -127 instead of -128? Remember: these are only
the minimums required by the spec. Some number representations (like sign and magnitude9 )
top off at ±127.
Let’s run the same table on my 64-bit, two’s complement system and see what comes out:
That’s a little more sensible, but we can see how my system has larger limits than the minimums in the
specification.
So what are the macros in <limits.h>?
8
Depends on if a char defaults to signed char or unsigned char
9
https://en.wikipedia.org/wiki/Signed_number_representations#Signed_magnitude_representation
10
My char is signed.
14.4. More Float: double and long double 91
Notice there’s a way hidden in there to determine if a system uses signed or unsigned chars. If CHAR_MAX
== UCHAR_MAX, it must be unsigned.
Also notice there’s no minimum macro for the unsigned variants—they’re just 0.
Parameter Definition
𝑠 sign (±1)
𝑏 base or radix of exponent representation (an
integer > 1)
𝑒 exponent (an integer between a minimum 𝑒𝑚𝑖𝑛
and a maximum 𝑒𝑚𝑎𝑥 )
𝑝 precision (the number of base-𝑏 digits in the
significand)
𝑓𝑘 nonnegative integers less than 𝑏 (the significand
digits)
But more particularly, only a certain number of significant decimal digits can be represented accurately.
How can you get more? You can use larger data types!
And we have a couple of them. We know about float already, but for more precision we have double.
And for even more precision, we have long double (unrelated to long int except by name).
The spec doesn’t go into how many bytes of storage each type should take, but on my system, we can see
the relative size increases:
|Type|sizeof| |:-|-:| |float|4| |double|8| |long double|16|
So each of the types (on my system) uses those additional bits for more precision.
But how much precision are we talking, here? How many decimal numbers can be represented by these
values?
Well, C provides us with a bunch of macros in <float.h> to help us figure that out.
It gets a little wonky if you are using a base-2 (binary) system for storing the numbers (which is virtually
everyone on the planet, probably including you), but bear with me while we figure it out.
On my system, FLT_DIG is 6, so I can be sure that if I print out a 6 digit float, I’ll get the same thing back.
(It could be more digits—some numbers will come back correctly with more digits. But 6 is definitely
coming back.)
For example, printing out floats following this pattern of increasing digits, we apparently make it to 8
digits before something goes wrong, but after that we’re back to 7 correct digits.
0.12345
0.123456
0.1234567
0.12345678
0.123456791 <-- Things start going wrong
0.1234567910
Let’s do another demo. In this code we’ll have two floats that both hold numbers that have FLT_DIG
significant decimal digits12 . Then we add those together, for what should be 12 significant decimal digits.
But that’s more than we can store in a float and correctly recover as a string—so we see when we print
it out, things start going wrong after the 7th significant digit.
1 #include <stdio.h>
2 #include <float.h>
3
4 int main(void)
5 {
6 // Both these numbers have 6 significant digits, so they can be
7 // stored accurately in a float:
12
This program runs as its comments indicate on a system with FLT_DIG of 6 that uses IEEE-754 base-2 floating point numbers.
Otherwise, you might get different output.
14.4. More Float: double and long double 93
9 float f = 3.14159f;
10 float g = 0.00000265358f;
11
(The above code has an f after the numeric constants—this indicates that the constant is type float, as
opposed to the default of double. More on this later.)
Remember that FLT_DIG is the safe number of digits you can store in a float and retrieve correctly.
Sometimes you might get one or two more out of it. But sometimes you’ll only get FLT_DIG digits back.
The sure thing: if you store any number of digits up to and including FLT_DIG in a float, you’re sure to
get them back correctly.
So that’s the story. FLT_DIG. The End.
…Or is it?
But what about those floating point numbers that aren’t in the gap? How many places do you need to print
those out accurately?
Another way to phrase this question is for any given floating point number, how many decimal digits do
I have to preserve if I want to convert the decimal number back into an identical floating point number?
That is, how many digits do I have to print in base 10 to recover all the digits in base 2 in the original
number?
Sometimes it might only be a few. But to be sure, you’ll want to convert to decimal with a certain safe
number of decimal places. That number is encoded in the following macros:
Macro Description
FLT_DECIMAL_DIG Number of decimal digits encoded in a float.
DBL_DECIMAL_DIG Number of decimal digits encoded in a double.
LDBL_DECIMAL_DIG Number of decimal digits encoded in a long
double.
DECIMAL_DIG Same as the widest encoding,
LDBL_DECIMAL_DIG.
Let’s see an example where DBL_DIG is 15 (so that’s all we can have in a constant), but DBL_DECIMAL_DIG
is 17 (so we have to convert to 17 decimal numbers to preserve all the bits of the original double).
Let’s assign the 15 significant digit number 0.123456789012345 to x, and let’s assign the 1 significant
digit number 0.0000000000000006 to y.
94 Chapter 14. Types II: Way More Types!
But let’s add them together. This should give 0.1234567890123456, but that’s more than DBL_DIG, so
strange things might happen… let’s look:
x + y not quite right: 0.12345678901234559 Should end in 4560!
That’s what we get for printing more than DBL_DIG, right? But check this out… that number, above, is
exactly representable as it is!
If we assign 0.12345678901234559 (17 digits) to z and print it, we get:
z is exact: 0.12345678901234559 17 digits correct! More than DBL_DIG!
If we’d truncated z down to 15 digits, it wouldn’t have been the same number. That’s why to preserve all
the bits of a double, we need DBL_DECIMAL_DIG and not just the lesser DBL_DIG.
All that being said, it’s clear that when we’re messing with decimal numbers in general, it’s not safe to
print more than FLT_DIG, DBL_DIG, or LDBL_DIG digits to be sensible in relation to the original base 10
numbers and any subsequent math.
But when converting from float to a decimal representation and back to float, definitely use
FLT_DECIMAL_DIG to do that so that all the bits are preserved exactly.
This is particularly problematic for beginner programmers who try to pad decimal numbers on the left
with 0 to line things up nice and pretty, inadvertently changing the base of the number:
int x = 11111; // Decimal 11111
int y = 00111; // Decimal 73 (Octal 111)
int z = 01111; // Decimal 585 (Octal 1111)
There’s no printf() format specifier for printing a binary number. You have to do it a character at a time
with bitwise operators.
The suffix can be uppercase or lowercase. And the U and L or LL can appear either one first.
Type Suffix
int None
long int L
long long int LL
unsigned int U
unsigned long int UL
unsigned long long int ULL
I mentioned in the table that “no suffix” means int… but it’s actually more complex than that.
So what happens when you have an unsuffixed number like:
int x = 1234;
Octal or Hexadecimal
Suffix Decimal Constant Constant
none int int
long int unsigned int
long int
unsigned long int
long long int
unsigned long long int
96 Chapter 14. Types II: Way More Types!
Octal or Hexadecimal
Suffix Decimal Constant Constant
u or U unsigned int unsigned int
unsigned long int unsigned long int
unsigned long long int unsigned long long int
What that’s saying is that, for example, if you specify a number like 123456789U, first C will see if it can
be unsigned int. If it doesn’t fit there, it’ll try unsigned long int. And then unsigned long long
int. It’ll use the smallest type that can hold the number.
Type Suffix
float F
double None
long double L
For example:
float x = 3.14f;
double x = 3.14;
long double x = 3.14L;
This whole time, though, we’ve just been doing this, right?
float x = 3.14;
Isn’t the left a float and the right a double? Yes! But C’s pretty good with automatic numeric conver-
sions, so it’s more common to have an unsuffixed floating point constant than not. More on that later.
However, when you print it, it will change the exponent so there is only one digit in front of the
decimal point.
• The plus can be left off the exponent, as it’s default, but this is uncommon in practice from what
I’ve seen.
1.2345e10 == 1.2345e+10
14
https://en.wikipedia.org/wiki/Scientific_notation
98 Chapter 14. Types II: Way More Types!
Chapter 15
In this chapter, we want to talk all about converting from one type to another. C has a variety of ways of
doing this, and some might be a little different that you’re used to in other languages.
Before we talk about how to make conversions happen, let’s talk about how they work when they do
happen.
These basically work like printf(), except they output to a string instead, and you can print that string
later, or whatever.
3 int main(void)
4 {
5 char s[10];
6 float f = 3.14159;
7
99
100 Chapter 15. Types III: Conversions
Function Description
atoi String to int
atof String to float
atol String to long int
atoll String to long long int
Though the spec doesn’t cop to it, the a at the beginning of the function stands for ASCII2 , so really
atoi() is “ASCII-to-integer”, but saying so today is a bit ASCII-centric.
4 int main(void)
5 {
6 char *pi = "3.14159";
7 float f;
8
9 f = atof(pi);
10
11 printf("%f\n", f);
12 }
But, like I said, we get undefined behavior from weird things like this:
int x = atoi("what"); // "What" ain't no number I ever heard of
(When I run that, I get 0 back, but you really shouldn’t count on that in any way. You could get something
completely different.)
For better error handling characteristics, let’s check out all those strtol functions, also in <stdlib.h>.
Not only that, but they convert to more types and more bases, too!
Function Description
strtol String to long int
strtoll String to long long int
strtoul String to unsigned long int
strtoull String to unsigned long long int
strtof String to float
strtod String to double
strtold String to long double
These functions all follow a similar pattern of use, and are a lot of people’s first experience with pointers
to pointers! But never fret—it’s easier than it looks.
Let’s do an example where we convert a string to an unsigned long, discarding error information (i.e. in-
formation about bad characters in the input string):
2
https://en.wikipedia.org/wiki/ASCII
15.1. String Conversions 101
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *s = "3490";
7
Notice a couple things there. Even though we didn’t deign to capture any information about error charac-
ters in the string, strtoul() won’t give us undefined behavior; it will just return 0.
Also, we specified that this was a decimal (base 10) number.
Does this mean we can convert numbers of different bases? Sure! Let’s do binary!
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *s = "101010"; // What's the meaning of this number?
7
12 printf("%lu\n", x); // 42
13 }
OK, that’s all fun and games, but what’s with that NULL in there? What’s that for?
That helps us figure out if an error occurred in the processing of the string. It’s a pointer to a pointer to a
char, which sounds scary, but isn’t once you wrap your head around it.
Let’s do an example where we feed in a deliberately bad number, and we’ll see how strtol() lets us
know where the first invalid digit is.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *s = "34x90"; // "x" is not a valid digit in base 10!
7 char *badchar;
8
15 printf("%lu\n", x); // 34
16
18 // points to it!
19
So there we have strtoul() modifying what badchar points to in order to show us where things went
wrong3 .
But what if nothing goes wrong? In that case, badchar will point to the NUL terminator at the end of the
string. So we can test for it:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *s = "3490"; // "x" is not a valid digit in base 10!
7 char *badchar;
8
15 if (*badchar == '\0') {
16 printf("Success! %lu\n", x);
17 } else {
18 printf("Partial conversion: %lu\n", x);
19 printf("Invalid character: %c\n", *badchar);
20 }
21 }
So there you have it. The atoi()-style functions are good in a controlled pinch, but the strtol()-style
functions give you far more control over error handling and the base of the input.
So… no. And 53? What is that? That’s the UTF-8 (and ASCII) code point for the character symbol '5'4
So how do we convert the character '5' (which apparently has value 53) into the value 5?
With one clever trick, that’s how!
The C Standard guarantees that these character will have code points that are in sequence and in this order:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
48 49 50 51 52 53 54 55 56 57
You see there that '5' is 53, just like we were getting. And '0' is 48.
So we can subtract '0' from any digit character to get its numeric value:
char c = '6';
And we can convert the other way, too, just by adding the value on.
int x = 6;
You might think this is a weird way to do this conversion, and by today’s standards, it certainly is. But
back in the olden days when computers were made literally out of wood, this was the method for doing
this conversion. And it wasn’t broke, so C never fixed it.
In that case, x and y get promoted to int by C before the math takes place.
The integer promotions take place during The Usual Arithmetic Conversions, with variadic functions8 ,
unary + and - operators, or when passing values to functions without prototypes9 .
These conversions answer questions about what happens when you mix types, like this:
int x = 3 + 1.2; // Mixing int and double
// 4.2 is converted to int
// 4 is stored in x
1. If one thing in the expression is a floating type, convert the other things to that floating type.
2. Otherwise, if both types are integer types, perform the integer promotions on each, then make the
operand types as big as they need to be hold the common largest value. Sometimes this involves
changing signed to unsigned.
If you want to know the gritty details, check out C11 §6.3.1.8. But you probably don’t.
Just generally remember that int types become float types if there’s a floating point type anywhere in there,
and the compiler makes an effort to make sure mixed integer types don’t overflow.
Finally, if you convert from one floating point type to another, the compiler will try to make an exact
conversion. If it can’t, it’ll do the best approximation it can. If the number is too large to fit in the type
you’re converting into, boom: undefined behavior!
15.4.3 void*
The void* type is interesting because it can be converted from or to any pointer type.
int x = 10;
8
Functions with a variable number of arguments.
9
This is rarely done because the compiler will complain and having a prototype is the Right Thing to do. I think this still works
for historic reasons, before prototypes were a thing.
15.5. Explicit Conversions 105
15.5.1 Casting
You can explicitly change the type of an expression by putting a new type in parentheses in front of it.
Some C devs frown on the practice unless absolutely necessary, but it’s likely you’ll come across some C
code with these in it.
Let’s do an example where we want to convert an int into a long so that we can store it in a long.
Note: this example is contrived and the cast in this case is completely unnecessary because the x + 12
expression would automatically be changed to long int to match the wider type of y.
int x = 10;
long int y = (long int)x + 12;
In that example, even those x was type int before, the expression (long int)x has type long int. We
say, “We cast x to long int.”
More commonly, you might see a cast being used to convert a void* into a specific pointer type so it can
be dereferenced.
A callback from the built-in qsort() function might display this behavior since it has void*s passed into
it:
int compar(const void *elem1, const void *elem2)
{
if (*((const int*)elem2) > *((const int*)elem1)) return 1;
if (*((const int*)elem2) < *((const int*)elem1)) return -1;
return 0;
}
One place you’ll see casts more commonly is to avoid a warning when printing pointer values with the
rarely-used %p which gets picky with anything other than a void*:
int x = 3490;
int *p = &x;
printf("%p\n", p);
Another place is with explicit pointer changes, if you don’t want to use an intervening void*, but these
are also pretty uncommon:
long x = 3490;
long *p = &x;
unsigned char *c = (unsigned char *)p;
A third place it’s often required is with the character conversion functions in <ctype.h> where you should
cast questionably-signed values to unsigned char to avoid undefined behavior.
Again, casting is rarely needed in practice. If you find yourself casting, there might be another way to do
the same thing, or maybe you’re casting unnecessarily.
Or maybe it is necessary. Personally, I try to avoid it, but am not afraid to use it if I have to.
Chapter 16
Now that we have some more types under our belts, turns out we can give these types some additional
attributes that control their behavior. These are the type qualifiers and storage-class specifiers.
16.1.1 const
This is the most common type qualifier you’ll see. It means the variable is constant, and any attempt to
modify it will result in a very angry compiler.
const int x = 2;
107
108 Chapter 16. Types IV: Qualifiers and Specifiers
Great, so we can’t change the thing the pointer points to, but we can change the pointer itself. What if we
want the other way around? We want to be able to change what the pointer points to, but not the pointer
itself?
Just move the const after the asterisk in the declaration:
int *const p; // We can't modify "p" with pointer arithmetic
Finally, if you have multiple levels of indirection, you should const the appropriate levels. Just because
a pointer is const, doesn’t mean the pointer it points to must also be. You can explicitly set them like in
the following examples:
char **p;
p++; // OK!
(*p)++; // OK!
char **const p;
p++; // Error!
(*p)++; // OK!
The compiler is warning us that the value on the right side of the assignment is const, but the one of the
left is not. And the compiler is letting us know that it is discarding the “const-ness” of the expression on
the right.
16.1. Type Qualifiers 109
That is, we can still try to do the following, but it’s just wrong. The compiler will warn, and it’s undefined
behavior:
const int x = 20;
int *p = &x;
16.1.2 restrict
TLDR: you never have to use this and you can ignore it every time you see it. If you use it correctly, you
will likely realize some performance gain. If you use it incorrectly, you will realize undefined behavior.
restrict is a hint to the compiler that a particular piece of memory will only be accessed by one pointer
and never another. (That is, there will be no aliasing of the particular object the restrict pointer points
to.) If a developer declares a pointer to be restrict and then accesses the object it points to in another
way (e.g. via another pointer), the behavior is undefined.
Basically you’re telling C, “Hey—I guarantee that this one single pointer is the only way I access this
memory, and if I’m lying, you can pull undefined behavior on me.”
And C uses that information to perform certain optimizations. For instance, if you’re dereferencing the
restrict pointer repeatedly in a loop, C might decide to cache the result in a register and only store the
final result once the loop completes. If any other pointer referred to that same memory and accessed it in
the loop, the results would not be accurate.
(Note that restrict has no effect if the object pointed to is never written to. It’s all about optimizations
surrounding writes to memory.)
Let’s write a function to swap two variables, and we’ll use the restrict keyword to assure C that we’ll
never pass in pointers to the same thing. And then let’s blow it and try passing in pointers to the same
thing.
1 void swap(int *restrict a, int *restrict b)
2 {
3 int t;
4
5 t = *a;
6 *a = *b;
7 *b = t;
8 }
9
10 int main(void)
11 {
12 int x = 10, y = 20;
13
14 swap(&x, &y); // OK! "a" and "b", above, point to different things
15
16 swap(&x, &x); // Undefined behavior! "a" and "b" point to the same thing
17 }
If we were to take out the restrict keywords, above, that would allow both calls to work safely. But
then the compiler might not be able to optimize.
restrict has block scope, that is, the restriction only lasts for the scope it’s used. If it’s in a parameter
list for a function, it’s in the block scope of that function.
If the restricted pointer points to an array, it only applies to the individual objects in the array. Other
pointers could read and write from the array as long as they didn’t read or write any of the same elements
as the restricted one.
110 Chapter 16. Types IV: Qualifiers and Specifiers
If it’s outside any function in file scope, the restriction covers the entire program.
You’re likely to see this in library functions like printf():
int printf(const char * restrict format, ...);
Again, that’s just telling the compiler that inside the printf() function, there will be only one pointer
that refers to any part of that format string.
One last note: if you’re using array notation in your function parameter for some reason instead of pointer
notation, you can use restrict like so:
void foo(int p[restrict]) // With no size
16.1.3 volatile
You’re unlikely to see or need this unless you’re dealing with hardware directly.
volatile tells the compiler that a value might change behind its back and should be looked up every
time.
An example might be where the compiler is looking in memory at an address that continuously updates
behind the scenes, e.g. some kind of hardware timer.
If the compiler decides to optimize that and store the value in a register for a protracted time, the value in
memory will update and won’t be reflected in the register.
By declaring something volatile, you’re telling the compiler, “Hey, the thing this points at might change
at any time for reasons outside this program code.”
volatile int *p;
16.1.4 _Atomic
This is an optional C feature that we’ll talk about in the Atomics chapter.
16.2.1 auto
You barely ever see this keyword, since auto is the default for block scope variables. It’s implied.
These are the same:
{
int a; // auto is the default...
auto int a; // So this is redundant
}
The auto keyword indicates that this object has automatic storage duration. That is, it exists in the scope
in which it is defined, and is automatically deallocated when the scope is exited.
One gotcha about automatic variables is that their value is indeterminate until you explicitly initialize
them. We say they’re full of “random” or “garbage” data, though neither of those really makes me happy.
In any case, you won’t know what’s in it unless you initialize it.
Always initialize all automatic variables before use!
16.2. Storage-Class Specifiers 111
16.2.2 static
This keyword has two meanings, depending on if the variable is file scope or block scope.
Let’s start with block scope.
3 void counter(void)
4 {
5 static int count = 1; // This is initialized one time
6
9 count++;
10 }
11
12 int main(void)
13 {
14 counter(); // "This has been called 1 time(s)"
15 counter(); // "This has been called 2 time(s)"
16 counter(); // "This has been called 3 time(s)"
17 counter(); // "This has been called 4 time(s)"
18 }
Finally, be advised that if you’re writing multithreaded programs, you have to be sure you don’t let multiple
threads trample the same variable.
16.2.3 extern
The extern storage-class specifier gives us a way to refer to objects in other source files.
Let’s say, for example, the file bar.c had the following as its entirety:
112 Chapter 16. Types IV: Qualifiers and Specifiers
1 // bar.c
2
3 int a = 37;
3 extern int a;
4
5 int main(void)
6 {
7 printf("%d\n", a); // 37, from bar.c!
8
9 a = 99;
10
We could have also made the extern int a in block scope, and it still would have referred to the a in
bar.c:
1 // foo.c
2
3 int main(void)
4 {
5 extern int a;
6
9 a = 99;
10
Now, if a in bar.c had been marked static. this wouldn’t have worked. static variables at file scope
are not visible outside that file.
A final note about extern on functions. For functions, extern is the default, so it’s redundant. You can
declare a function static if you only want it visible in a single source file.
16.2.4 register
This is a keyword to hint to the compiler that this variable is frequently-used, and should be made as fast
as possible to access. The compiler is under no obligation to agree to it.
Now, modern C compiler optimizers are pretty effective at figuring this out themselves, so it’s rare to see
these days.
But if you must:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 register int a; // Make "a" as fast to use as possible.
6
8 printf("%d\n", a);
9 }
It does come at a price, however. You can’t take the address of a register:
register int a;
int *p = &a; // COMPILER ERROR! Can't take address of a register
Interestingly, for the equivalent with array notation, gcc only warns:
register int a[] = {11, 22, 33, 44, 55};
with:
warning: ISO C forbids subscripting ‘register’ array
The fact that you can’t take the address of a register variable frees the compiler up to make optimizations
around that assumption if it hasn’t figured them out already. Also adding register to a const variable
prevents one from accidentally passing its pointer to another function that willfully ignore its constness1 .
A bit of historic backstory, here: deep inside the CPU are little dedicated “variables” called registers2 .
They are super fast to access compared to RAM, so using them gets you a speed boost. But they’re not in
RAM, so they don’t have an associated memory address (which is why you can’t take the address-of or
get a pointer to them).
But, like I said, modern compilers are really good at producing optimal code, using registers whenever
possible regardless of whether or not you specified the register keyword. Not only that, but the spec
allows them to just treat it as if you’d typed auto, if they want. So no guarantees.
16.2.5 _Thread_local
When you’re using multiple threads and you have some variables in either global or static block scope,
this is a way to make sure that each thread gets its own copy of the variable. This’ll help you avoid race
conditions and threads stepping on each other’s toes.
If you’re in block scope, you have to use this along with either extern or static.
Also, if you include <threads.h>, you can use the rather more palatable thread_local as an alias for
the uglier _Thread_local.
More information can be found in the Threads section.
1
https://gustedt.wordpress.com/2010/08/17/a-common-misconsception-the-register-keyword/
2
https://en.wikipedia.org/wiki/Processor_register
114 Chapter 16. Types IV: Qualifiers and Specifiers
Chapter 17
Multifile Projects
So far we’ve been looking at toy programs that for the most part fit in a single file. But complex C
programs are made up of many files that are all compiled and linked together into a single executable.
In this chapter we’ll check out some of the common patterns and practices for putting together larger
projects.
In that examples, foo.c and bar.c get built into the executable named foo.
So let’s take a look at the source file bar.c:
1 // File bar.c
2
3 #include <stdio.h>
4
5 int main(void)
6 {
7 printf("%d\n", add(2, 3)); // 5!
8 }
115
116 Chapter 17. Multifile Projects
See how from main() we call add()—but add() is in a completely different source file! It’s in bar.c,
while the call to it is in foo.c!
If we build this with:
gcc -o foo foo.c bar.c
(Or you might get a warning. Which you should not ignore. Never ignore warnings in C; address them
all.)
If you recall from the section on prototypes, implicit declarations are banned in modern C and there’s no
legitimate reason to introduce them into new code. We should fix it.
What implicit declaration means is that we’re using a function, namely add() in this case, without
letting C know anything about it ahead of time. C wants to know what it returns, what types it takes as
arguments, and things such as that.
We saw how to fix that earlier with a function prototype. Indeed, if we add one of those to foo.c before
we make the call, everything works well:
1 // File foo.c
2
3 #include <stdio.h>
4
7 int main(void)
8 {
9 printf("%d\n", add(2, 3)); // 5!
10 }
No more error!
But that’s a pain—needing to type in the prototype every time you want to use a function. I mean, we
used printf() right there and didn’t need to type in a prototype; what gives?
If you remember from what back with hello.c at the beginning of the book, we actually did include the
prototype for printf()! It’s in the file stdio.h! And we included that with #include!
Can we do the same with our add() function? Make a prototype for it and put it in a header file?
Sure!
Header files in C have a .h extension by default. And they often, but not always, have the same name as
their corresponding .c file. So let’s make a bar.h file for our bar.c file, and we’ll stick the prototype in
it:
1 // File bar.h
2
And now let’s modify foo.c to include that file. Assuming it’s in the same directory, we include it inside
double quotes (as opposed to angle brackets):
1 // File foo.c
2
3 #include <stdio.h>
4
7 int main(void)
8 {
17.2. Dealing with Repeated Includes 117
Notice how we don’t have the prototype in foo.c anymore—we included it from bar.h. Now any file
that wants that add() functionality can just #include "bar.h" to get it, and you don’t need to worry
about typing in the function prototype.
As you might have guessed, #include literally includes the named file right there in your source code,
just as if you’d typed it in.
And building and running:
./foo
5
What we need to do is make it so that if a file gets included once, subsequent #includes for that file are
ignored.
The stuff that we’re about to do is so common that you should just automatically do it every time
you make a header file!
And the common way to do this is with a preprocessor variable that we set the first time we #include
the file. And then for subsequent #includes, we first check to make sure that the variable isn’t defined.
For that variable name, it’s super common to take the name of the header file, like bar.h, make it upper-
case, and replace the period with an underscore: BAR_H.
So put a check at the very, very top of the file where you see if it’s already been included, and effectively
comment the whole thing out if it has.
(Don’t put a leading underscore (because a leading underscore followed by a capital letter is reserved) or
a double leading underscore (because that’s also reserved.))
1 #ifndef BAR_H // If BAR_H isn't defined...
2 #define BAR_H // Define it (with no particular value)
3
4 // File bar.h
5
This will effectively cause the header file to be included only a single time, no matter how many places
try to #include it.
118 Chapter 17. Multifile Projects
Voila, we’ve produced an executable foo from the two object files.
But you’re thinking, why bother? Can’t we just:
gcc -o foo foo.c bar.c
1
https://en.wikipedia.org/wiki/Boids
Chapter 18
When you run a program, it’s actually you talking to the shell, saying, “Hey, please run this thing.” And
the shell says, “Sure,” and then tells the operating system, “Hey, could you please make a new process
and run this thing?” And if all goes well, the OS complies and your program runs.
But there’s a whole world outside your program in the shell that can be interacted with from within C.
We’ll look at a few of those in this chapter.
1
Historially, MS-DOS and Windows programs would do this differently than Unix. In Unix, the shell would expand the wildcard
into all matching files before your program saw it, whereas the Microsoft variants would pass the wildcard expression into the
program to deal with. In any case, there are arguments that get passed into the program.
119
120 Chapter 18. The Outside Environment
It’s a little weird, because the zeroth argument is the name of the executable, itself. But that’s just some-
thing to get used to. The arguments themselves follow directly.
Source:
1 #include <stdio.h>
2
Whoa! What’s going on with the main() function signature? What’s argc and argv2 (pronounced arg-
cee and arg-vee)?
Let’s start with the easy one first: argc. This is the argument count, including the program name, itself.
If you think of all the arguments as an array of strings, which is exactly what they are, then you can think
of argc as the length of that array, which is exactly what it is.
And so what we’re doing in that loop is going through all the argvs and printing them out one at a time,
so for a given input:
./foo i like turtles
11 total += value;
12 }
13
14 printf("%d\n", total);
15 }
Sample runs:
2
Since they’re just regular parameter names, you don’t actually have to call them argc and argv. But it’s so very idiomatic to
use those names, if you get creative, other C programmers will look at you with a suspicious eye, indeed!
18.1. Command Line Arguments 121
$ ./add
0
$ ./add 1
1
$ ./add 1 2
3
$ ./add 1 2 3
6
$ ./add 1 2 3 4
10
Of course, it might puke if you pass in a non-integer, but hardening against that is left as an exercise to
the reader.
is always true!
This might seem pointless, but it turns out to be useful in a couple places; we’ll take a look at one of those
right now.
Now, it’s been convenient to think of argv as an array of strings, i.e. an array of char*s, so this made
sense:
int main(int argc, char *argv[])
Yeah, that’s a pointer to a pointer, all right! If it makes it easier, think of it as a pointer to a string. But
really, it’s a pointer to a value that points to a char.
Also recall that these are equivalent:
argv[i]
*(argv + i)
6 int total = 0;
7
15 total += value;
16 }
17
18 printf("%d\n", total);
19 }
Personally, I use array notation to access argv, but have seen this style floating around, as well.
But if you modify argv[0] like so, being careful that the new string "Hi! " is the same length
as the old one "./foo":
strcpy(argv[0], "Hi! ");
and then run ps while the program ./foo is still executing, we’ll see this instead:
4079 tty1 S 0:00 Hi!
in C: if execution reaches the end of main() without finding a return, it automatically does a return
0.
But what does the 0 mean? What other numbers can we put there? And how are they used?
The spec is both clear and vague on the matter, as is common. Clear because it spells out what you can
do, but vague in that it doesn’t particularly limit it, either.
Nothing for it but to forge ahead and figure it out!
Let’s get Inception4 for a second: turns out that when you run your program, you’re running it from
another program.
Usually this other program is some kind of shell5 that doesn’t do much on its own except launch other
programs.
But this is a multi-phase process, especially visible in command-line shells:
1. The shell launches your program
2. The shell typically goes to sleep (for command-line shells)
3. Your program runs
4. Your program terminates
5. The shell wakes up and waits for another command
Now, there’s a little piece of communication that takes place between steps 4 and 5: the program can
return a status value that the shell can interrogate. Typically, this value is used to indicate the success or
failure of your program, and, if a failure, what type of failure.
This value is what we’ve been returning from main(). That’s the status.
Now, the C spec allows for two different status values, which have macro names defined in <stdlib.h>:
Status Description
EXIT_SUCCESS or 0 Program terminated successfully.
EXIT_FAILURE Program terminated with an error.
Let’s write a short program that multiplies two numbers from the command line. We’ll require that you
specify exactly two values. If you don’t, we’ll print an error message, and exit with an error status.
1 #include <stdio.h>
2 #include <stdlib.h>
3
Now if we try to run this, we get the expected effect until we specify exactly the right number of command-
line arguments:
$ ./mult
usage: mult x y
4
https://en.wikipedia.org/wiki/Inception
5
https://en.wikipedia.org/wiki/Shell_(computing)
124 Chapter 18. The Outside Environment
$ ./mult 3 4 5
usage: mult x y
$ ./mult 3 4
12
But that doesn’t really show the exit status that we returned, does it? We can get the shell to print it out,
though. Assuming you’re running Bash or another POSIX shell, you can use echo $? to see it6 .
Let’s try:
$ ./mult
usage: mult x y
$ echo $?
1
$ ./mult 3 4 5
usage: mult x y
$ echo $?
1
$ ./mult 3 4
12
$ echo $?
0
Interesting! We see that on my system, EXIT_FAILURE is 1. The spec doesn’t spell this out, so it could
be any number. But try it; it’s probably 1 on your system, too.
HOSTTYPE=x86_64
IFS=$' \t\n'
Notice they are in the form of key/value pairs. For example, one key is HOSTTYPE and its value is x86_64.
From a C perspective, all values are strings, even if they’re numbers7 .
So, anyway! Long story short, it’s possible to get these values from inside your C program.
Let’s write a program that uses the standard getenv() function to look up a value that you set in the shell.
getenv() will return a pointer to the value string, or else NULL if the environment variable doesn’t exist.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *val = getenv("FROTZ"); // Try to get the value
7
In this way, you can set up data in environment variables, and you can get it in your C code and modify
your behavior accordingly.
5 int main(void)
6 {
7 for (char **p = environ; *p != NULL; p++) {
8 printf("%s\n", *p);
9 }
10
Use getenv() if at all possible because it’s more portable. But if you have to iterate over environment
variables, using environ might be the way to go.
Another non-standard way to get the environment variables is as a parameter to main(). It works much
the same way, but you avoid needing to add your extern environ variable. Not even the POSIX spec
supports this9 as far as I can tell, but it’s common in Unix land.
1 #include <stdio.h>
2
Just like using environ but even less portable. It’s good to have goals.
9
https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
Chapter 19
The C Preprocessor
Before your program gets compiled, it actually runs through a phase called preprocessing. It’s almost like
there’s a language on top of the C language that runs first. And it outputs the C code, which then gets
compiled.
We’ve already seen this to an extent with #include! That’s the C Preprocessor! Where it sees that
directive, it includes the named file right there, just as if you’d typed it in there. And then the compiler
builds the whole thing.
But it turns out it’s a lot more powerful than just being able to include things. You can define macros that
are substituted… and even macros that take arguments!
19.1 #include
Let’s start with the one we’ve already seen a bunch. This is, of course, a way to include other sources in
your source. Very commonly used with header files.
While the spec allows for all kinds of behavior with #include, we’re going to take a more pragmatic
approach and talk about the way it works on every system I’ve ever seen.
We can split header files into two categories: system and local. Things that are built-in, like stdio.h,
stdlib.h, math.h, and so on, you can include with angle brackets:
#include <stdio.h>
#include <stdlib.h>
The angle brackets tell C, “Hey, don’t look in the current directory for this header file—look in the system-
wide include directory instead.”
Which, of course, implies that there must be a way to include local files from the current directory. And
there is: with double quotes:
#include "myheader.h"
Or you can very probably look in relative directories using forward slashes and dots, like this:
#include "mydir/myheader.h"
#include "../someheader.py"
Don’t use a backslash (\) for your path separators in your #include! It’s undefined behavior! Use
forward slash (/) only, even on Windows.
In summary, used angle brackets (< and >) for the system includes, and use double quotes (") for your
personal includes.
127
128 Chapter 19. The C Preprocessor
6 int main(void)
7 {
8 printf("%s, %f\n", HELLO, PI);
9 }
On lines 3 and 4 we defined a couple macros. Wherever these appear elsewhere in the code (line 8), they’ll
be substituted with the defined values.
From the C compiler’s perspective, it’s exactly as if we’d written this, instead:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 printf("%s, %f\n", "Hello, world", 3.14159);
6 }
See how HELLO was replaced with "Hello, world" and PI was replaced with 3.14159? From the
compiler’s perspective, it’s just like those values had appeared right there in the code.
Note that the macros don’t have a specific type, per se. Really all that happens is they get replaced
wholesale with whatever they’re #defined as. If the resulting C code is invalid, the compiler will puke.
You can also define a macro with no value:
#define EXTRA_HAPPY
in that case, the macro exists and is defined, but is defined to be nothing. So anyplace it occurs in the text
will just be replaced with nothing. We’ll see a use for this later.
It’s conventional to write macro names in ALL_CAPS even though that’s not technically required.
Overall, this gives you a way to define constant values that are effectively global and can be used any
place. Even in those places where a const variable won’t work, e.g. in switch cases and fixed array
lengths.
That said, the debate rages online whether a typed const variable is better than #define macro in the
general case.
It can also be used to replace or modify keywords, a concept completely foreign to const, though this
practice should be used sparingly.
1 #include <stdio.h>
2
3 #define EXTRA_HAPPY
4
5 int main(void)
6 {
7
8 #ifdef EXTRA_HAPPY
9 printf("I'm extra happy!\n");
10 #endif
11
12 printf("OK!\n");
13 }
In that example, we define EXTRA_HAPPY (to be nothing, but it is defined), then on line 8 we check to see
if it is defined with an #ifdef directive. If it is defined, the subsequent code will be included up until the
#endif.
So because it is defined, the code will be included for compilation and the output will be:
I'm extra happy!
OK!
then it wouldn’t be defined, and the code wouldn’t be included in compilation. And the output would just
be:
OK!
It’s important to remember that these decisions happen at compile time! The code actually gets compiled
or removed depending on the condition. This is in contrast to a standard if statement that gets evaluated
while the program is running.
12 #ifndef EXTRA_HAPPY
13 printf("I'm just regular\n");
14 #endif
int x = 12;
This demonstrates how a macro persists across files and multiple #includes. If it’s not yet defined, let’s
define it and compile the whole header file.
130 Chapter 19. The C Preprocessor
But the next time it’s included, we see that MYHEADER_H is defined, so we don’t send the header file to the
compiler—it gets effectively removed.
19.3.3 #else
But that’s not all we can do! There’s also an #else that we can throw in the mix.
Let’s mod the previous example:
8 #ifdef EXTRA_HAPPY
9 printf("I'm extra happy!\n");
10 #else
11 printf("I'm just regular\n");
12 #endif
Now if EXTRA_HAPPY is not defined, it’ll hit the #else clause and print:
I'm just regular
3 #define HAPPY_FACTOR 1
4
5 int main(void)
6 {
7
8 #if HAPPY_FACTOR == 0
9 printf("I'm not happy!\n");
10 #elif HAPPY_FACTOR == 1
11 printf("I'm just regular\n");
12 #else
13 printf("I'm extra happy!\n");
14 #endif
15
16 printf("OK!\n");
17 }
Again, for the unmatched #if clauses, the compiler won’t even see those lines. For the above code, after
the preprocessor gets finished with it, all the compiler sees is:
1 #include <stdio.h>
2
3 int main(void)
4 {
5
8 printf("OK!\n");
9 }
One hackish thing this is used for is to comment out large numbers of lines quickly1 .
1
You can’t always just wrap the code in /* */ comments because those won’t nest.
19.3. Conditional Compilation 131
If you put an #if 0 (“if false”) at the front of the block to be commented out and an #endif at the end,
you can get this effect:
#if 0
printf("All this code"); /* is effectively */
printf("commented out"); // by the #if 0
#endif
You might have noticed that there’s no #elifdef or #elifndef directives. How can we get the same
effect with #if? That is, what if I wanted this:
#ifdef FOO
x = 2;
#elifdef BAR // ERROR: Not supported by standard C
x = 3;
#endif
As are these:
#ifndef FOO
#if !defined FOO
#if !defined(FOO) // Parentheses optional
Notice how we can use the standard logical NOT operator (!) for “not defined”.
So now we’re back in #if land and we can use #elif with impunity!
This broken code:
#ifdef FOO
x = 2;
#elifdef BAR // ERROR: Not supported by standard C
x = 3;
#endif
3 int main(void)
4 {
5 #define GOATS
6
7 #ifdef GOATS
8 printf("Goats detected!\n"); // prints
9 #endif
132 Chapter 19. The C Preprocessor
10
13 #ifdef GOATS
14 printf("Goats detected, again!\n"); // doesn't print
15 #endif
16 }
Macro Description
__DATE__ The date of compilation—like when you’re
compiling this file—in Mmm dd yyyy format
__TIME__ The time of compilation in hh:mm:ss format
__FILE__ A string containing this file’s name
__LINE__ The line number of the file this macro appears on
__func__ The name of the function this appears in, as a
string2
__STDC__ Defined with 1 if this is a standard C compiler
__STDC_HOSTED__ This will be 1 if the compiler is a hosted
implementation3 , otherwise 0
__STDC_VERSION__ This version of C, a constant long int in the
form yyyymmL, e.g. 201710L
3 int main(void)
4 {
5 printf("This function: %s\n", __func__);
6 printf("This file: %s\n", __FILE__);
7 printf("This line: %d\n", __LINE__);
8 printf("Compiled on: %s %s\n", __DATE__, __TIME__);
9 printf("C Version: %ld\n", __STDC_VERSION__);
10 }
2
This isn’t really a macro—it’s technically an identifier. But it’s the only predefined identifier and it feels very macro-like, so
I’m including it here. Like a rebel.
3
A hosted implementation basically means you’re running the full C standard, probably on an operating system of some kind.
Which you probably are. If you’re running on bare metal in some kind of embedded system, you’re probably on a standalone
implementation.
19.4. Built-in Macros 133
__FILE__, __func__ and __LINE__ are particularly useful to report error conditions in messages to
developers. The assert() macro in <assert.h> uses these to call out where in the code the assertion
failed.
19.4.1.1 __STDC_VERSION__s
In case you’re wondering, here are the version numbers for different major releases of the C Language
Spec:
Macro Description
__STDC_ISO_10646__ If defined, wchar_t holds Unicode values,
otherwise something else
__STDC_MB_MIGHT_NEQ_WC__ A 1 indicates that the values in multibyte
characters might not map equally to values in wide
characters
__STDC_UTF_16__ A 1 indicates that the system uses UTF-16
encoding in type char16_t
__STDC_UTF_32__ A 1 indicates that the system uses UTF-32
encoding in type char32_t
__STDC_ANALYZABLE__ A 1 indicates the code is analyzable4
__STDC_IEC_559__ 1 if IEEE-754 (aka IEC 60559) floating point is
supported
__STDC_IEC_559_COMPLEX__ 1 if IEC 60559 complex floating point is supported
__STDC_LIB_EXT1__ 1 if this implementation supports a variety of
“safe” alternate standard library functions (they
have _s suffixes on the name)
__STDC_NO_ATOMICS__ 1 if this implementation does not support
_Atomic or <stdatomic.h>
__STDC_NO_COMPLEX__ 1 if this implementation does not support complex
types or <complex.h>
__STDC_NO_THREADS__ 1 if this implementation does not support
<threads.h>
__STDC_NO_VLA__ 1 if this implementation does not support
variable-length arrays
4
OK, I know that was a cop-out answer. Basically there’s an optional extension compilers can implement wherein they agree to
limit certain types of undefined behavior so that the C code is more amenable to static code analysis. It is unlikely you’ll need to
use this.
134 Chapter 19. The C Preprocessor
5 int main(void)
6 {
7 printf("%d\n", SQR(12)); // 144
8 }
What that’s saying is “everywhere you see SQR with some value, replace it with that value times itself”.
So line 7 will be changed to:
7 printf("%d\n", 12 * 12); // 144
What happened?
If we follow the macro expansion, we get
7 printf("%d\n", 3 + 4 * 3 + 4); // 19!
Oops! Since multiplication takes precedence, we do the 4 × 3 = 12 first, and get 3 + 12 + 4 = 19. Not
what we were after.
So we have to fix this to make it right.
This is so common that you should automatically do it every time you make a parameterized math
macro!
The fix is easy: just add some parentheses!
3 #define SQR(x) (x) * (x) // Better... but still not quite good enough!
But we actually still have the same problem which might manifest if we have a higher-precedence operator
than multiply (*) nearby.
So the safe, proper way to put the macro together is to wrap the whole thing in additional parentheses, like
so:
19.5. Macros with Arguments 135
Just make it a habit to do that when you make a math macro and you can’t go wrong.
Let’s do some macros that solve for 𝑥 using the quadratic formula. Just in case you don’t have it on the
top of your head, it says for equations of the form:
𝑎𝑥2 + 𝑏𝑥 + 𝑐 = 0
So that gets us some math. But let’s define one more that we can use as arguments to printf() to print
both answers.
// macro replacement
// |-----------| |----------------------------|
#define QUAD(a, b, c) QUADP(a, b, c), QUADM(a, b, c)
That’s just a couple values separated by a comma—and we can use that as a “combined” argument of sorts
to printf() like this:
printf("x = %f or x = %f\n", QUAD(2, 10, 5));
8 int main(void)
9 {
10 printf("2*x^2 + 10*x + 5 = 0\n");
11 printf("x = %f or x = %f\n", QUAD(2, 10, 5));
12 }
Plugging in either of those values gives us roughly zero (a bit off because the numbers aren’t exact):
8 int main(void)
9 {
10 printf("%d %f %s %d\n", X(5, 4, 3.14, "Hi!", 12));
11 }
for output:
130 3.140000 Hi! 12
19.5.4 Stringification
Already mentioned, just above, you can turn any argument into a string by preceding it with a # in the
replacement text.
For example, we could print anything as a string with this macro and printf():
#define STR(x) #x
printf("%s\n", STR(3.14159));
Let’s see if we can use this to greater effect so that we can pass any int variable name into a macro, and
have it print out it’s name and value.
1 #include <stdio.h>
2
5 int main(void)
6 {
7 int a = 5;
8
19.5.5 Concatenation
We can concatenate two arguments together with ##, as well. Fun times!
#define CAT(a, b) a ## b
3 #define PRINT_NUMS_TO_PRODUCT(a, b) do { \
4 int product = (a) * (b); \
5 for (int i = 0; i < product; i++) { \
6 printf("%d\n", i); \
7 } \
8 } while(0)
9
10 int main(void)
11 {
12 PRINT_NUMS_TO_PRODUCT(2, 4); // Outputs numbers from 0 to 7
13 }
5 int main(void)
6 {
7 int i = 0;
8
9 if (i == 0)
10 FOO(i);
11 else
12 printf(":-(\n");
13
14 printf("%d\n", i);
15 }
if (i == 0) {
(i)++;
}; // <-- Trouble with a capital-T!
else
printf(":-(\n");
The ; puts an end to the if statement, so the else is just floating out there illegally5 .
So wrap that multiline macro with a do-while(0).
I want something like this to happen (assuming the ASSERT() is on line 220 of foo.c):
if (!(x < 20)) {
fprintf(stderr, "foo.c:220: assertion x < 20 failed: ");
fprintf(stderr, "x must be under 20\n");
exit(1);
}
We can get the filename out of the __FILE__ macro, and the line number from __LINE__. The message
is already a string, but x < 20 is not, so we’ll have to stringify it with #. We can make a multiline macro
by using backslash escapes at the end of the line.
#define ASSERT(c, m) \
do { \
if (!(c)) { \
fprintf(stderr, __FILE__ ":%d: assertion %s failed: %s\n", \
__LINE__, #c, m); \
exit(1); \
} \
} while(0)
(It looks a little weird with __FILE__ out front like that, but remember it is a string literal, and string
literals next to each other are automagically concatenated. __LINE__ on the other hand, it’s just an int.)
And that works! If I run this:
int x = 30;
Very nice!
The only thing left is a way to turn it on and off, and we could do that with conditional compilation.
Here’s the complete example:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define ASSERT_ENABLED 1
5
6 #if ASSERT_ENABLED
7 #define ASSERT(c, m) \
8 do { \
9 if (!(c)) { \
10 fprintf(stderr, __FILE__ ":%d: assertion %s failed: %s\n", \
11 __LINE__, #c, m); \
12 exit(1); \
13 } \
14 } while(0)
15 #else
16 #define ASSERT(c, m) // Empty macro if not enabled
17 #endif
18
19 int main(void)
20 {
21 int x = 30;
22
Some compilers have a non-standard complementary #warning directive that will output a warning but
not stop compilation, but this is not in the C11 spec.
There are all kinds of #pragma directives documented across all four corners of the globe.
All unrecognized #pragmas are ignored by the compiler.
For example:
#pragma STDC FP_CONTRACT OFF
#pragma STDC CX_LIMITED_RANGE ON
which is just cosmetic; the line with the solitary # can be deleted with no ill effect.
Or maybe for cosmetic consistency, like this:
#
#ifdef FOO
x = 2;
#endif
#
#if BAR == 17
x = 12;
#endif
#
Turns out there’s a lot more you can do with structs than we’ve talked about, but it’s just a big pile of
miscellaneous things. So we’ll throw them in this chapter.
If you’re good with struct basics, you can round out your knowledge here.
Turns out we have more power in these initializers than we’d originally shared. Exciting!
For one thing, if you have a nested substructure like the following, you can initialize members of that
substructure by following the variable names down the line:
struct foo x = {.a.b.c=12};
3 struct cabin_information {
4 int window_count;
5 int o2level;
6 };
7
8 struct spaceship {
9 char *manufacturer;
10 struct cabin_information ci;
11 };
12
13 int main(void)
14 {
15 struct spaceship s = {
16 .manufacturer="General Products",
17 .ci.window_count = 8, // <-- NESTED INITIALIZER!
18 .ci.o2level = 21
19 };
20
143
144 Chapter 20. structs II: More Fun with structs
Check out lines 16-17! That’s where we’re initializing members of the struct cabin_information in
the definition of s, our struct spaceship.
And here is another option for that same initializer—this time we’ll do something more standard-looking,
but either approach works:
15 struct spaceship s = {
16 .manufacturer="General Products",
17 .ci={
18 .window_count = 8,
19 .o2level = 21
20 }
21 };
Now, as if the above information isn’t spectacular enough, we can also mix in array initializers in there,
too.
Let’s change this up to get an array of passenger information in there, and we can check out how the
initializers work in there, too.
1 #include <stdio.h>
2
3 struct passenger {
4 char *name;
5 int covid_vaccinated; // Boolean
6 };
7
8 #define MAX_PASSENGERS 8
9
10 struct spaceship {
11 char *manufacturer;
12 struct passenger passenger[MAX_PASSENGERS];
13 };
14
15 int main(void)
16 {
17 struct spaceship s = {
18 .manufacturer="General Products",
19 .passenger = {
20 // Initialize a field at a time
21 [0].name = "Gridley, Lewis",
22 [0].covid_vaccinated = 0,
23
24 // Or all at once
25 [7] = {.name="Brown, Teela", .covid_vaccinated=1},
26 }
27 };
28
Okaaaaay. So we have a struct, but it has no name, so we have no way of using it later? Seems pretty
pointless.
Admittedly, in that example, it is. But we can still make use of it a couple ways.
One is rare, but since the anonymous struct represents a type, we can just put some variable names after
it and use them.
struct { // <-- No name!
char *name;
int leg_count, speed;
} a, b, c; // 3 variables of this struct type
a.name = "antelope";
c.leg_count = 4; // for example
animal a, b, c;
a.name = "antelope";
c.leg_count = 4; // for example
Personally, I don’t use many anonymous structs. I think it’s more pleasant to see the entire struct
animal before the variable name in a declaration.
struct node {
int data;
struct node *next;
};
It’s important to note that next is a pointer. This is what allows the whole thing to even build. Even
though the compiler doesn’t know what the entire struct node looks like yet, all pointers are the same
size.
Here’s a cheesy linked list program to test it out:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 struct node {
5 int data;
6 struct node *next;
7 };
8
9 int main(void)
10 {
11 struct node *head;
12
22 // Traverse it
23 for (struct node *cur = head; cur != NULL; cur = cur->next) {
24 printf("%d\n", cur->data);
25 }
26 }
But that has 8 hardcoded as the maximum length of a string, and that’s not much. What if we did something
20.4. Flexible Array Members 147
clever and just malloc()d some extra space at the end after the struct, and then let the data overflow into
that space?
Because data is the last field of the struct, if we overflow that field, it runs out into space that we already
allocated! For this reason, this trick only works if the short array is the last field in the struct.
// Copy more than 8 bytes!
In fact, there was a common compiler workaround for doing this, where you’d allocate a zero length array
at the end:
struct len_string {
int length;
char data[0];
};
And then every extra byte you allocated was ready for use in that string.
Because data is the last field of the struct, if we overflow that field, it runs out into space that we already
allocated!
// Copy more than 8 bytes!
But, of course, actually accessing the data beyond the end of that array is undefined behavior! In these
modern times, we no longer deign to resort to such savagery.
Luckily for us, we can still get the same effect with C99 and later, but now it’s legal.
Let’s just change our above definition to have no size for the array1 :
struct len_string {
int length;
char data[];
};
Again, this only works if the flexible array member is the last field in the struct.
And then we can allocate all the space we want for those strings by malloc()ing larger than the struct
len_string, as we do in this example that makes a new struct len_string from a C string:
struct len_string *len_string_from_c_string(char *s)
{
int len = strlen(s);
ls->length = len;
return ls;
}
1
Technically we say that it has an incomplete type.
148 Chapter 20. structs II: More Fun with structs
3 struct foo {
4 int a;
5 char b;
6 int c;
7 char d;
8 };
9
10 int main(void)
11 {
12 printf("%zu\n", sizeof(int) + sizeof(char) + sizeof(int) + sizeof(char));
13 printf("%zu\n", sizeof(struct foo));
14 }
They’re not the same! The compiler has added 6 bytes of padding to help it be more performant. Maybe
you got different output with your compiler, but unless you’re forcing it, you can’t be sure there’s no
padding.
20.6 offsetof
In the previous section, we saw that the compiler could inject padding bytes at will inside a structure.
What if we needed to know where those were? We can measure it with offsetof, defined in <stddef.h>.
Let’s modify the code from above to print the offsets of the individual fields in the struct:
1 #include <stdio.h>
2 #include <stddef.h>
3
4 struct foo {
5 int a;
6 char b;
7 int c;
8 char d;
9 };
10
11 int main(void)
12 {
13 printf("%zu\n", offsetof(struct foo, a));
14 printf("%zu\n", offsetof(struct foo, b));
15 printf("%zu\n", offsetof(struct foo, c));
16 printf("%zu\n", offsetof(struct foo, d));
17 }
2
Though some compilers have options to force this to occur—search for __attribute__((packed)) to see how to do this with
GCC.
20.7. Fake OOP 149
indicating that we’re using 4 bytes for each of the fields. It’s a little weird, because char is only 1 byte,
right? The compiler is putting 3 padding bytes after each char so that all the fields are 4 bytes long.
Presumably this will run faster on my CPU.
struct child {
struct parent super; // MUST be first
int c, d;
};
Then we are able to pass a pointer to a struct child to a function that expects either that or a pointer
to a struct parent!
Because struct parent super is the first item in the struct child, a pointer to any struct child
is the same as a pointer to that super field3 .
Let’s set up an example here. We’ll make structs as above, but then we’ll pass a pointer to a struct
child to a function that needs a pointer to a struct parent… and it’ll still work.
1 #include <stdio.h>
2
3 struct parent {
4 int a, b;
5 };
6
7 struct child {
8 struct parent super; // MUST be first
9 int c, d;
10 };
11
3
super isn’t a keyword, incidentally. I’m just stealing some OOP terminology.
150 Chapter 20. structs II: More Fun with structs
23
29 int main(void)
30 {
31 struct child c = {.super.a=1, .super.b=2, .c=3, .d=4};
32
33 print_child(&c);
34 print_parent(&c); // Also works even though it's a struct child!
35 }
See what we did on the last line of main()? We called print_parent() but passed a struct child*
as the argument! Even though print_parent() needs the argument to point to a struct parent, we’re
getting away with it because the first field in the struct child is a struct parent.
Again, this works because a pointer to a struct has the same value as a pointer to the first field in that
struct.
20.8 Bit-Fields
In my experience, these are rarely used, but you might see them out there from time to time, especially in
lower-level applications that pack bits together into larger spaces.
Let’s take a look at some code to demonstrate a use case:
1 #include <stdio.h>
2
3 struct foo {
4 unsigned int a;
5 unsigned int b;
6 unsigned int c;
7 unsigned int d;
8 };
9
10 int main(void)
11 {
12 printf("%zu\n", sizeof(struct foo));
13 }
For me, this prints 16. Which makes sense, since unsigneds are 4 bytes on my system.
But what if we knew that all the values that were going to be stored in a and b could be stored in 5 bits,
and the values in c, and d could be stored in 3 bits? That’s only a total 16 bits. Why have 128 bits reserved
for them if we’re only going to use 16?
20.8. Bit-Fields 151
Well, we can tell C to pretty-please try to pack these values in. We can specify the maximum number of
bits that values can take (from 1 up the size of the containing type).
We do this by putting a colon after the field name, followed by the field width in bits.
3 struct foo {
4 unsigned int a:5;
5 unsigned int b:5;
6 unsigned int c:3;
7 unsigned int d:3;
8 };
Now when I ask C how big my struct foo is, it tells me 4! It was 16 bytes, but now it’s only 4. It has
“packed” those 4 values down into 4 bytes, which is a four-fold memory savings.
The tradeoff is, of course, that the 5-bit fields can only hold values from 0-31 and the 3-bit fields can only
hold values from 0-7. But life’s all about compromise, after all.
In that example, since a is not adjacent to c, they are both “packed” in their own ints.
So we have one int each for a, b, c, and d. Since my ints are 4 bytes, that’s a grand total of 16 bytes.
A quick rearrangement yields some space savings from 16 bytes down to 12 bytes (on my system):
struct foo { // sizeof(struct foo) == 12 (for me)
unsigned int a:1;
unsigned int c:1;
unsigned int b;
unsigned int d;
};
And now, since a is next to c, the compiler puts them together into a single int.
So we have one int for a combined a and c, and one int each for b and d. For a grand total of 3 ints,
or 12 bytes.
Put all your bitfields together to get the compiler to combine them.
For example, let’s say you have a byte where the top 2 bits have a meaning, the bottom 1 bit has a meaning,
but the middle 5 bits do not get used by you4 .
And that works—in our code we use a and b, but never dummy. It’s just there to eat up 5 bits to make sure
a and b are in the “required” (by this contrived example) positions within the byte.
C allows us a way to clean this up: unnamed bit-fields. You can just leave the name (dummy) out in this
case, and C is perfectly happy for the same effect:
struct foo {
unsigned char a:2;
unsigned char :5; // <-- unnamed bit-field!
unsigned char b:1;
};
the compiler packs all those into a single unsigned int. But what if you needed a and b in one int, and
c and d in a different one?
There’s a solution for that: put an unnamed bit-field of width 0 where you want the compiler to start anew
with packing bits in a different int:
struct foo {
unsigned int a:1;
unsigned int b:2;
unsigned int :0; // <--Zero-width unnamed bit-field
unsigned int c:3;
unsigned int d:4;
};
It’s analogous to an explicit page break in a word processor. You’re telling the compiler, “Stop packing
bits in this unsigned, and start packing them in the next one.”
By adding the zero-width unnamed bit field in that spot, the compiler puts a and b in one unsigned int,
and c and d in another unsigned int. Two total, for a size of 8 bytes on my system (unsigned ints
are 4 bytes each).
4
Assuming 8-bit chars, i.e. CHAR_BIT == 8.
20.9. Unions 153
20.9 Unions
These are basically just like structs, except the fields overlap in memory. The union will be only large
enough for the largest field, and you can only use one field at a time.
It’s a way to reuse the same memory space for different types of data.
You declare them just like structs, except it’s union. Take a look at this:
union foo {
int a, b, c, d, e, f;
float g, h;
char i, j, k, l;
};
Now, that’s a lot of fields. If this were a struct, my system would tell me it took 36 bytes to hold it all.
But it’s a union, so all those fields overlap in the same stretch of memory. The biggest one is int (or
float), taking up 4 bytes on my system. And, indeed, if I ask for the sizeof the union foo, it tells me
4!
The tradeoff is that you can only portably use one of those fields at a time. However…
3 union foo {
4 float b;
5 short a;
6 };
7
8 int main(void)
9 {
10 union foo x;
11
12 x.b = 3.14159;
13
because under the hood, the object representation for the float 3.14159 was the same as the object repre-
sentation for the short 4048. On my system. Your results may vary.
In this example, we see that the union has ints and floats in it. And we get pointers to the union, but
we cast them to int* and float* types (the cast silences compiler warnings). And then if we dereference
those, we see that they have the values we stored directly in the union.
1 #include <stdio.h>
2
3 union foo {
4 int a, b, c, d, e, f;
5 float g, h;
6 char i, j, k, l;
7 };
8
9 int main(void)
10 {
11 union foo x;
12
16 x.a = 12;
17 printf("%d\n", x.a); // 12
18 printf("%d\n", *foo_int_p); // 12, again
19
20 x.g = 3.141592;
21 printf("%f\n", x.g); // 3.141592
22 printf("%f\n", *foo_float_p); // 3.141592, again
23 }
The reverse is also true. If we have a pointer to a type inside the union, we can cast that to a pointer to
the union and access its members.
union foo x;
int *foo_int_p = (int *)&x; // Pointer to int field
union foo *p = (union foo *)foo_int_p; // Back to pointer to union
All this just lets you know that, under the hood, all these values in a union start at the same place in
memory, and that’s the same as where the entire union is.
char *p;
};
struct b {
int x; //
float y; // Common initial sequence
20.9. Unions 155
double *p;
short z;
};
Do you see it? It’s that they start with int followed by float—that’s the common initial sequence. The
members in the sequence of the structs have to be compatible types. And we see that with x and y,
which are int and float respectively.
Now let’s build a union of these:
union foo {
struct a sa;
struct b sb;
};
What this rule tells us is that we’re guaranteed that the members of the common initial sequences are
interchangeable in code. That is:
• f.sa.x is the same as f.sb.x.
and
• f.sa.y is the same as f.sb.y.
Because fields x and y are both in the common initial sequence.
Also, the names of the members in the common initial sequence don’t matter—all that matters is that the
types are the same.
All together, this allows us a way to safely add some shared information between structs in the union.
The best example of this is probably using a field to determine the type of struct out of all the structs
in the union that is currently “in use”.
That is, if we weren’t allowed this and we passed the union to some function, how would that function
know which member of the union was the one it should look at?
Take a look at these structs. Note the common initial sequence:
1 #include <stdio.h>
2
3 struct common {
4 int type; // common initial sequence
5 };
6
7 struct antelope {
8 int type; // common initial sequence
9
10 int loudness;
11 };
12
13 struct octopus {
14 int type; // common initial sequence
15
16 int sea_creature;
17 float intelligence;
18 };
So far, nothing special has happened here. It seems like the type field is completely useless.
But now let’s make a generic function that prints a union animal. It has to somehow be able to tell if
it’s looking at a struct antelope or a struct octopus.
Because of the magic of common initial sequences, it can look up the animal type in any of these places
for a particular union animal x:
int type = x.common.type; \\ or...
int type = x.antelope.type; \\ or...
int type = x.octopus.type;
And, as you might have guessed, the struct common is there so code can agnostically look at the type
without mentioning a particular animal.
36 case OCTOPUS:
37 printf("Octopus : sea_creature=%d\n", x->octopus.sea_creature);
38 printf(" intelligence=%f\n", x->octopus.intelligence);
39 break;
40
41 default:
42 printf("Unknown animal type\n");
43 }
44
45 }
46
47 int main(void)
48 {
49 union animal a = {.antelope.type=ANTELOPE, .antelope.loudness=12};
50 union animal b = {.octopus.type=OCTOPUS, .octopus.sea_creature=1,
51 .octopus.intelligence=12.8};
52
53 print_animal(&a);
54 print_animal(&b);
55 }
See how on line 29 we’re just passing in the union—we have no idea what type of animal struct is in
use within it.
But that’s OK! Because on line 31 we check the type to see if it’s an antelope or an octopus. And then we
can look at the proper struct to get the members.
It’s definitely possible to get this same effect using just structs, but you can do it this way if you want
the memory-saving effects of a union.
20.10. Unions and Unnamed Structs 157
That defines a variable s that is of anonymous struct type (because the struct has no name tag), with
members x and y.
So things like this are valid:
s.x = 34;
s.y = 90;
Turns out you can drop those unnamed structs in unions just like you might expect:
union foo {
struct { // unnamed!
int x, y;
} a;
struct { // unnamed!
int z, w;
} b;
};
f.a.x = 1;
f.a.y = 2;
f.b.z = 3;
f.b.w = 4;
No problem!
3 struct foo {
4 int x, y;
5 };
6
12 int main(void)
13 {
14 struct foo a = f(); // Copy is made
158 Chapter 20. structs II: More Fun with structs
15
Fun fact: if you do this, you can use the . operator right off the function call:
16 printf("%d %d\n", f().x, f().y);
We’ve talked about how char types are actually just small integer types… but it’s the same for a character
in single quotes.
But a string in double quotes is type const char *.
Turns out there are few more types of strings and characters, and it leads down one of the most infamous
rabbit holes in the language: the whole multibyte/wide/Unicode/localization thingy.
We’re going to peer into that rabbit hole, but not go in. …Yet!
But what if we want some special characters in there that we can’t type on the keyboard because they
don’t exist (e.g. “€”), or even if we want a character that’s a single quote? We clearly can’t do this:
char t = ''';
To do these things, we use something called escape sequences. These are the backslash character (\)
followed by another character. The two (or more) characters together have special meaning.
For our single quote character example, we can put an escape (that is, \) in front of the central single quote
to solve it:
char t = '\'';
Now C knows that \' means just a regular quote we want to print, not the end of the character sequence.
You can say either “backslash” or “escape” in this context (“escape that quote”) and C devs will know
what you’re talking about. Also, “escape” in this context is different than your Esc key or the ASCII ESC
code.
Code Description
\n Newline character—when printing, continue subsequent output on the next line
\' Single quote—used for a single quote character constant
\" Double quote—used for a double quote in a string literal
1
I just made up that number, but it’s probably not far off
159
160 Chapter 21. Characters and Strings II
Code Description
\\ Backslash—used for a literal \ in a string or character
Here are some examples of the escapes and what they output when printed.
printf("Use \\n for newline\n"); // Use \n for newline
printf("Say \"hello\"!\n"); // Say "hello"!
printf("%c\n", '\''); // '
Code Description
\a Alert. This makes the terminal make a sound or flash, or both!
\b Backspace. Moves the cursor back a character. Doesn’t delete the character.
\f Formfeed. This moves to the next “page”, but that doesn’t have much modern meaning.
On my system, this behaves like \v.
\r Return. Move to the beginning of the same line.
\t Horizontal tab. Moves to the next horizontal tab stop. On my machine, this lines up on
columns that are multiples of 8, but YMMV.
\v Vertical tab. Moves to the next vertical tab stop. On my machine, this moves to the
same column on the next line.
\? Literal question mark. Sometimes you need this to avoid trigraphs, as shown below.
4 int main(void)
5 {
6 for (int i = 10; i >= 0; i--) {
7 printf("\rT minus %d second%s... \b", i, i != 1? "s": "");
8
15 printf("\rLiftoff! \n");
16 }
Quite a few things are happening on line 7. First of all, we lead with a \r to get us to the beginning of the
current line, then we overwrite whatever’s there with the current countdown. (There’s ternary operator
out there to make sure we print 1 second instead of 1 seconds.)
Also, there’s a space after the ... That’s so that we properly overwrite the last . when i drops from 10
to 9 and we get a column narrower. Try it without the space to see what I mean.
And we wrap it up with a \b to back up over that space so the cursor sits at the exact end of the line in an
aesthetically-pleasing way.
21.1. Escape Sequences 161
Note that line 14 also has a lot of spaces at the end to overwrite the characters that were already there from
the countdown.
Finally, we have a weird fflush(stdout) in there, whatever that means. Short answer is that most termi-
nals are line buffered by default, meaning they don’t actually display anything until a newline character is
encountered. Since we don’t have a newline (we just have \r), without this line, the program would just
sit there until Liftoff! and then print everything all in one instant. fflush() overrides this behavior
and forces output to happen right now.
Code Description
\123 Embed the byte with octal value 123, 3 digits exactly.
\x4D Embed the byte with hex value 4D, 2 digits.
\u2620 Embed the Unicode character at code point with hex value 2620, 4 digits.
162 Chapter 21. Characters and Strings II
Code Description
\U0001243F Embed the Unicode character at code point with hex value 1243F, 8 digits.
Here’s an example of the less-commonly used octal notation to represent the letter B in between A and C.
Normally this would be used for some kind of special unprintable character, but we have other ways to
do that, below, and this is just an octal demo:
printf("A\102C\n"); // 102 is `B` in ASCII/UTF-8
Note there’s no leading zero on the octal number when you include it this way. But it does need to be
three characters, so pad with leading zeros if you need to.
But far more common is to use hex constants these days. Here’s a demo that you shouldn’t use, but it
demos embedding the UTF-8 bytes 0xE2, 0x80, and 0xA2 in a string, which corresponds to the Unicode
“bullet” character (•).
printf("\xE2\x80\xA2 Bullet 1\n");
printf("\xE2\x80\xA2 Bullet 2\n");
printf("\xE2\x80\xA2 Bullet 3\n");
Produces the following output if you’re on a UTF-8 console (or probably garbage if you’re not):
• Bullet 1
• Bullet 2
• Bullet 3
But that’s a crummy way to do Unicode. You can use the escapes \u (16-bit) or \U (32-bit) to just refer
to Unicode by code point number. The bullet is 2022 (hex) in Unicode, so you can do this and get more
portable results:
printf("\u2022 Bullet 1\n");
printf("\u2022 Bullet 2\n");
printf("\u2022 Bullet 3\n");
Be sure to pad \u with enough leading zeros to get to four characters, and \U with enough to get to eight.
For example, that bullet could be done with \U and four leading zeros:
printf("\U00002022 Bullet 1\n");
163
164 Chapter 22. Enumerated Types: enum
Y=18,
Z=-2
};
if values are omitted, numbering continues counting in the positive direction from whichever value was
last specified. For example:
enum {
A, // 0, default starting value
B, // 1
C=4, // 4, manually set
D, // 5
E, // 6
F=3 // 3, manually set
G, // 4
H // 5
}
It’s gotten more popular in languages of the recent decades so you might be pleased to see it.
22.1.3 Scope
enums scope as you’d expect. If at file scope, the whole file can see it. If in a block, it’s local to that block.
It’s really common for enums to be defined in header files so they can be #included at file scope.
22.1.4 Style
As you’ve noticed, it’s common to declare the enum symbols in uppercase (with underscores).
This isn’t a requirement, but is a very, very common idiom.
enum resource {
SHEEP,
WHEAT,
WOOD,
BRICK,
ORE
};
if (r == BRICK) {
printf("I'll trade you a brick for two sheep.\n");
}
You can also typedef these, of course, though I personally don’t like to.
typedef enum {
SHEEP,
WHEAT,
WOOD,
BRICK,
ORE
} RESOURCE;
RESOURCE r = BRICK;
Another shortcut that’s legal but rare is to declare variables when you declare the enum:
// Declare an enum and some initialized variables of that type:
enum {
SHEEP,
WHEAT,
WOOD,
BRICK,
ORE
} r = BRICK, s = WOOD;
You can also give the enum a name so you can use it later, which is probably what you want to do in most
cases:
// Declare an enum and some initialized variables of that type:
In short, enums are a great way to write nice, scoped, typed, clean code.
166 Chapter 22. Enumerated Types: enum
Chapter 23
Here’s where we cover some intermediate and advanced pointer usage. If you don’t have pointers down
well, review the previous chapters on pointers and pointer arithmetic before starting on this stuff.
3 int main(void)
4 {
5 int x = 3490; // Type: int
6 int *p = &x; // Type: pointer to an int
7
Straightforward enough, right? We have two types represented: int and int*, and we set up p to point
to x. Then we can dereference p on line 8 and print out the value 3490.
But, like we said, we can have a pointer to any variable… so does that mean we can have a pointer to p?
In other words, what type is this expression?
1
There’s some devil in the details with values that are stored in registers only, but we can safely ignore that for our purposes
here. Also the C spec makes no stance on these “register” things beyond the register keyword, the description for which doesn’t
mention registers.
167
168 Chapter 23. Pointers III: Pointers to Pointers and More
If x is an int, then &x is a pointer to an int that we’ve stored in p which is type int*. Follow? (Repeat
this paragraph until you do!)
And therefore &p is a pointer to an int*, AKA a “pointer to a pointer to an int”. AKA “int-pointer-
pointer”.
Got it? (Repeat the previous paragraph until you do!)
We write this type with two asterisks: int **. Let’s see it in action.
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int x = 3490; // Type: int
6 int *p = &x; // Type: pointer to an int
7 int **q = &p; // Type: pointer to pointer to int
8
Let’s make up some pretend addresses for the above values as examples and see what these three variables
might look like in memory. The address values, below are just made up by me for example purposes:
Indeed, let’s try it for real on my computer2 and print out the pointer values with %p and I’ll do the same
table again with actual references (printed in hex).
You can see those addresses are the same except the last byte, so just focus on those.
On my system, ints are 4 bytes, which is why we’re seeing the address go up by 4 from x to p3 and then
goes up by 8 from p to q. On my system, all pointers are 8 bytes.
Does it matter if it’s an int* or an int**? Is one more bytes than the other? Nope! Remember that all
pointers are addresses, that is indexes into memory. And on my machine you can represent an index with
8 bytes… doesn’t matter what’s stored at that index.
Now check out what we did there on line 9 of the previous example: we double dereferenced q to get back
to our 3490.
This is the important bit about pointers and pointers to pointers:
• You can get a pointer to anything with & (including to a pointer!)
2
You’re very likely to get different numbers on yours.
3
There is absolutely nothing in the spec that says this will always work this way, but it happens to work this way on my system.
23.1. Pointers to Pointers 169
• You can get the thing a pointer points to with * (including a pointer!)
So you can think of & as being used to make pointers, and * being the inverse—it goes the opposite
direction of &—to get to the thing pointed to.
In terms of type, each time you &, that adds another pointer level to the type.
And each time you use dereference (*), it does the opposite:
Note that you can use multiple *s in a row to quickly dereference, just like we saw in the example code
with **q, above. Each one strips away one level of indirection.
means that you can’t modify p. Trying to p++ would give you a compile-time error.
But how does that work with int ** or int ***? Where does the const go, and what does it mean?
Let’s start with the simple bit. The const right next to the variable name refers to that variable. So if you
want an int*** that you can’t change, you can do this:
int ***const p;
And that works, too. Now we can’t modify q, or the pointer q points to.
return dest;
}
(There are some good examples of post-increment and post-decrement in there for you to study, as well.)
It’s important to note that the version, above, is probably less efficient than the one that comes with your
system.
But you can pass pointers to anything into it, and it’ll copy those objects. Could be int*, struct ani-
mal*, or anything.
Let’s do another example that prints out the object representation bytes of a struct so we can see if
there’s any padding in there and what values it has5 .
1 #include <stdio.h>
2
3 struct foo {
4 char a;
5 int b;
6 };
7
8 int main(void)
9 {
10 struct foo x = {0x12, 0x12345678};
11 unsigned char *p = (unsigned char *)&x;
12
What we have there is a struct foo that’s built in such a way that should encourage a compiler to inject
padding bytes (though it doesn’t have to). And then we get an unsigned char * to the first byte of the
struct foo variable x.
From there, all we need to know is the sizeof x and we can loop through that many bytes, printing out
the values (in hex for ease).
Running this gives a bunch of numbers as output. I’ve annotated it below to identify where the values
were stored:
12 | x.a == 0x12
AB |
BF | padding bytes with "random" value
26 |
78 |
56 | x.b == 0x12345678
34 |
12 |
On all systems, sizeof(char) is 1, and we see that first byte at the top of the output holding the value
0x12 that we stored there.
Then we have some padding bytes—for me, these varied from run to run.
5
Your C compiler is not required to add padding bytes, and the values of any padding bytes that are added are indeterminate.
172 Chapter 23. Pointers III: Pointers to Pointers and More
Finally, on my system, sizeof(int) is 4, and we can see those 4 bytes at the end. Notice how they’re
the same bytes as are in the hex value 0x12345678, but strangely in reverse order6 .
So that’s a little peek under the hood at the bytes of a more complex entity in memory.
Personally, I always use NULL when I mean NULL, but you might see some other variants from time to
time. Though '\0' (a byte with all bits set to zero) will also compare equal, it’s weird to compare it to
a pointer; you should compare NULL against the pointer. (Of course, lots of times in string processing,
you’re comparing the thing the pointer points to to '\0', and that’s right.)
0 is called the null pointer constant, and, when compared to or assigned into another pointer, it is converted
to a null pointer of the same type.
Additionally, if you feel like being signed, you can use intptr_t to the same effect.
int a = 1;
int *p = &a;
But the following isn’t good because int and float are not compatible types:
int a = 1;
float *p = (float *)&a;
Here’s a demo program that does some aliasing. It takes a variable v of type int32_t and aliases it to
a pointer to a struct words. That struct has two int16_ts in it. These types are incompatible, so
we’re in violation of strict aliasing rules. The compiler will assume that these two pointers never point to
the same object… but we’re making it so they do. Which is naughty of us.
Let’s see if we can break something.
1 #include <stdio.h>
2 #include <stdint.h>
3
4 struct words {
5 int16_t v[2];
6 };
7
19 int main(void)
20 {
21 int32_t v = 0x12345678;
22
25 fun(&v, pw);
26 }
See how I pass in the two incompatible pointers to fun()? One of the types is int32_t* and the other is
struct words*.
But they both point to the same object: the 32-bit value initialized to 0x12345678.
So if we look at the fields in the struct words, we should see the two 16-bit halves of that number.
Right?
And in the fun() loop, we increment the pointer to the int32_t. That’s it. But since the struct points
to that same memory, it, too, should be updated to the same value.
So let’s run it and get this, with the 32-bit value on the left and the two 16-bit portions on the right. It
should match8 :
12345679, 1234-5679
1234567a, 1234-567a
1234567b, 1234-567b
8
I’m printing out the 16-bit values reversed since I’m on a little-endian machine and it makes it easier to read here.
174 Chapter 23. Pointers III: Pointers to Pointers and More
1234567c, 1234-567c
1234567d, 1234-567d
They’re off by one! But they point to the same memory! How could this be? Answer: it’s undefined
behavior to alias memory like that. Anything is possible, except not in a good way.
If your code violates strict aliasing rules, whether it works or not depends on how someone decides to
compile it. And that’s a bummer since that’s beyond your control. Unless you’re some kind of omnipotent
deity.
Unlikely, sorry.
GCC can be forced to not use the strict aliasing rules with -fno-strict-aliasing. Compiling the demo
program, above, with -O3 and this flag causes the output to be as expected.
Lastly, type punning is using pointers of different types to look at the same data. Before strict aliasing,
this kind of things was fairly common:
int a = 0x12345678;
short b = *((short *)&a); // Violates strict aliasing
If you want to do type punning (relatively) safely, see the section on Unions and Type Punning.
ptrdiff_t d = g - f; // difference is 40
And you can print it by prefixing the integer format specifier with t:
printf("%td\n", d); // Print decimal: 40
printf("%tX\n", d); // Print hex: 28
This can be useful for passing a pointer to a function into another function as an argument. Then the
second one could call whatever was passed in.
The tricky part with these, though, is that C needs to know the type of the variable that is the pointer to
the function.
And it would really like to know all the details.
Like “this is a pointer to a function that takes two int arguments and returns void”.
How do you write all that down so you can declare a variable?
Well, it turns out it looks very much like a function prototype, except with some extra parentheses:
// Declare p to be a pointer to a function.
// This function returns a float, and takes two ints as arguments.
Also notice that you don’t have to give the parameters names. But you can if you want; they’re just
ignored.
// Declare p to be a pointer to a function.
// This function returns a float, and takes two ints as arguments.
So now that we know how to declare a variable, how do we know what to assign into it? How do we get
the address of a function?
Turns out there’s a shortcut just like with getting a pointer to an array: you can just refer to the bare
function name without parens. (You can put an & in front of this if you like, but it’s unnecessary and not
idiomatic.)
Once you have a pointer to a function, you can call it just by adding parens and an argument list.
Let’s do a simple example where I effectively make an alias for a function by setting a pointer to it. Then
we’ll call it.
This code prints out 3490:
1 #include <stdio.h>
2
3 void print_int(int n)
4 {
5 printf("%d\n", n);
6 }
7
8 int main(void)
9 {
10 // Assign p to point to print_int:
11
Notice how the type of p represents the return value and parameter types of print_int. It has to, or else
C will complain about incompatible pointer types.
One more example here shows how we might pass a pointer to a function as an argument to another
function.
We’ll write a function that takes a couple integer arguments, plus a pointer to a function that operates on
those two arguments. Then it prints the result.
176 Chapter 23. Pointers III: Pointers to Pointers and More
1 #include <stdio.h>
2
17 printf("%d\n", result);
18 }
19
20 int main(void)
21 {
22 print_math(add, 5, 7); // 12
23 print_math(mult, 5, 7); // 35
24 }
Take a moment to digest that. The idea here is that we’re going to pass a pointer to a function to
print_math(), and it’s going to call that function to do some math.
This way we can change the behavior of print_math() by passing another function into it. You can see
we do that on lines 22-23 when we pass in pointers to functions add and mult, respectively.
Now, on line 13, I think we can all agree the function signature of print_math() is a sight to behold.
And, if you can believe it, this one is actually pretty straight-forward compared to some things you can
construct10 .
But let’s digest it. Turns out there are only three parameters, but they’re a little hard to see:
// op x y
// |-----------------| |---| |---|
void print_math(int (*op)(int, int), int x, int y)
The first, op, is a pointer to a function that takes two ints as arguments and returns an int. This matches
the signatures for both add() and mult().
The second and third, x and y, are just standard int parameters.
Slowly and deliberately let your eyes play over the signature while you identify the working parts. One
thing that always stands out for me is the sequence (*op)(, the parens and the asterisk. That’s the give-
away it’s a pointer to a function.
Finally, jump back to the Pointers II chapter for a pointer-to-function example using the built-in qsort().
10
The Go Programming Language drew its type declaration syntax inspiration from the opposite of what C does.
Chapter 24
Bitwise Operations
These numeric operations effectively allow you to manipulate individual bits in variables, fitting since C
is such a low-level langauge1 .
If you’re not familiar with bitwise operations, Wikipedia has a good bitwise article2 .
Note how they’re similar to the Boolean operators && and ||.
These have assignment shorthand variants similar to += and -=:
1
Not that other languages don’t do this—they do. It is interesting how many modern languages use the same operators for bitwise
that C does.
2
https://en.wikipedia.org/wiki/Bitwise_operation
177
178 Chapter 24. Bitwise Operations
Watch for undefined behavior: no negative shifts, and no shifts that are larger than the size of the promoted
left operand.
Also watch for implementation-defined behavior: if you right-shift a negative number, the results are
implementation-defined. (It’s perfectly fine to right-shift a signed int, just make sure it’s positive.)
Chapter 25
Variadic Functions
Variadic is a fancy word for functions that take arbitrary numbers of arguments.
A regular function takes a specific number of arguments, for example:
int add(int x, int y)
{
return x + y;
}
You can only call that with exactly two arguments which correspond to parameters x and y.
add(2, 3);
add(5, 12);
But if you try it with more, the compiler won’t let you:
add(2, 3, 4); // ERROR
add(5); // ERROR
This leads us to one of the limitations of variadic functions in C: they must have at least one argument.
But aside from that, they’re pretty flexible, even allows arguments to have different types just like
printf() does.
179
180 Chapter 25. Variadic Functions
int main(void)
{
func(2, 3, 4, 5, 6);
}
So, great, we can get that first argument that’s in variable a, but what about the rest of the arguments?
How do you get to them?
Here’s where the fun begins!
14 total += n;
15 }
16
19 return total;
20 }
21
22 int main(void)
23 {
24 printf("%d\n", add(4, 6, 2, -4, 17)); // 6 + 2 - 4 + 17 = 21
25.3. va_list Functionality 181
(Note that when printf() is called, it uses the number of %ds (or whatever) in the format string to know
how many more arguments there are!)
If the syntax of va_arg() is looking strange to you (because of that loose type name floating around in
there), you’re not alone. These are implemented with preprocessor macros in order to get all the proper
magic in there.
Let’s make a function my_printf() that works just like printf() except it takes an extra argument up
front.
1 #include <stdio.h>
2 #include <stdarg.h>
3
8 // Do my custom work
9 printf("The serial number is: %d\n", serial);
10
16 return rv;
17 }
18
19 int main(void)
20 {
21 int x = 10;
22 float y = 3.2;
23
See what we did there? On lines 12-14 we started a new va_list variable, and then just passed it right
into vprintf(). And it knows just want to do with it, because it has all the printf() smarts built-in.
We still have to call va_end() when we’re done, though, so don’t forget that!
Chapter 26
Localization is the process of making your app ready to work well in different locales (or countries).
As you might know, not everyone uses the same character for decimal points or for thousands separators…
or for currency.
These locales have names, and you can select one to use. For example, a US locale might write a number
like:
100,000.00
Whereas in Brazil, the same might be written with the commas and decimal points swapped:
100.000,00
Makes it easier to write your code so it ports to other nationalities with ease!
Well, sort of. Turns out C only has one built-in locale, and it’s limited. The spec really leaves a lot of
ambiguity here; it’s hard to be completely portable.
But we’ll do our best!
You’ll want to call that so that the program gets initialized with your current locale.
Getting into more details, there is one more thing you can do and stay portable:
setlocale(LC_ALL, "C"); // Use the default C locale
but that’s called by default every time your program starts, so there’s not much need to do it yourself.
In that second string, you can specify any locale supported by your system. This is completely system-
dependent, so it will vary. On my system, I can specify this:
setlocale(LC_ALL, "en_US.UTF-8"); // Non-portable!
And that’ll work. But it’s only portable to systems which have that exact same name for that exact same
locale, and you can’t guarantee it.
By passing in an empty string ("") for the second argument, you’re telling C, “Hey, figure out what the
current locale on this system is so I don’t have to tell you.”
183
184 Chapter 26. Locale and Internationalization
How can you write that code without going insane? Luckily, once you call setlocale(LC_ALL, ""),
you can just look these up with a call to localeconv():
struct lconv *x = localeconv();
This function returns a pointer to a statically-allocated struct lconv that has all that juicy information
you’re looking for.
First, some conventions. An _p_ means “positive”, and _n_ means “negative”, and int_ means “inter-
national”. Though a lot of these are type char or char*, most (or the strings they point to) are actually
treated as integers2 .
Before we go further, know that CHAR_MAX (from <limits.h>) is the maximum value that can be held in
a char. And that many of the following char values use that to indicate the value isn’t available in the
given locale.
Field Description
char *mon_decimal_point Decimal pointer character for money, e.g. ".".
char *mon_thousands_sep Thousands separator character for money, e.g. ",".
char *mon_grouping Grouping description for money (see below).
char *positive_sign Positive sign for money, e.g. "+" or "".
char *negative_sign Negative sign for money, e.g. "-".
char *currency_symbol Currency symbol, e.g. "$".
char frac_digits When printing monetary amounts, how many digits to print past the
decimal point, e.g. 2.
char p_cs_precedes 1 if the currency_symbol comes before the value for a non-negative
monetary amount, 0 if after.
char n_cs_precedes 1 if the currency_symbol comes before the value for a negative
monetary amount, 0 if after.
char p_sep_by_space Determines the separation of the currency symbol from the value
for non-negative amounts (see below).
char n_sep_by_space Determines the separation of the currency symbol from the value
for negative amounts (see below).
char p_sign_posn Determines the positive_sign position for non-negative values.
char p_sign_posn Determines the positive_sign position for negative values.
char *int_curr_symbol International currency symbol, e.g. "USD ".
char int_frac_digits International value for frac_digits.
char int_p_cs_precedes International value for p_cs_precedes.
char int_n_cs_precedes International value for n_cs_precedes.
char int_p_sep_by_space International value for p_sep_by_space.
char int_n_sep_by_space International value for n_sep_by_space.
char int_p_sign_posn International value for p_sign_posn.
char int_n_sign_posn International value for n_sign_posn.
1
“This planet has—or rather had—a problem, which was this: most of the people living on it were unhappy for pretty much of
the time. Many solutions were suggested for this problem, but most of these were largely concerned with the movement of small
green pieces of paper, which was odd because on the whole it wasn’t the small green pieces of paper that were unhappy.” —The
Hitchhiker’s Guide to the Galaxy, Douglas Adams
2
Remember that char is just a byte-sized integer.
26.2. Getting the Monetary Locale Settings 185
These are groups of three. Group 0 (just left of the decimal) has 3 digits. Group 1 (next group to the left)
has 3 digits, and the last one also has 3.
So we could describe these groups, from the right (the decimal) to the left with a bunch of integer values
representing the group sizes:
3 3 3
but that’s crazy. Luckily, we can specify 0 to indicate that the previous group size repeats:
3 0
Which means to repeat every 3. That would handle $100, $1,000, $10,000, $10,000,000, $100,000,000,000,
and so on.
You can go legitimately crazy with these to indicate some weird groupings.
For example:
4 3 2 1 0
would indicate:
$1,0,0,0,0,00,000,0000.00
One more value that can occur is CHAR_MAX. This indicates that no more grouping should occur, and can
appear anywhere in the array, including the first value.
3 2 CHAR_MAX
would indicate:
100000000,00,000.00
for example.
And simply having CHAR_MAX in the first array position would tell you there was to be no grouping at all.
Value Description
0 No space between currency symbol and value.
1 Separate the currency symbol (and sign, if any) from the value with a space.
2 Separate the sign symbol from the currency symbol (if adjacent) with a
space, otherwise separate the sign symbol from the value with a space.
186 Chapter 26. Locale and Internationalization
Value Description
0 Put parens around the value and the currency symbol.
1 Put the sign string in front of the currency symbol and value.
2 Put the sign string after the currency symbol and value.
3 Put the sign string directly in front of the currency symbol.
4 Put the sign string directly behind the currency symbol.
Macro Description
LC_ALL Set all of the following to the given locale.
LC_COLLATE Controls the behavior of the strcoll() and strxfrm() functions.
LC_CTYPE Controls the behavior of the character-handling functions3 .
LC_MONETARY Controls the values returned by localeconv().
LC_NUMERIC Controls the decimal point for the printf() family of functions.
LC_TIME Controls time formatting of the strftime() and wcsftime() time and date
printing functions.
It’s pretty common to see LC_ALL being set, but, hey, at least you have options.
3
Except for isdigit() and isxdigit().
26.3. Localization Specifics 187
Also I should point out that LC_CTYPE is one of the biggies because it ties into wide characters, a significant
can of worms that we’ll talk about later.
188 Chapter 26. Locale and Internationalization
Chapter 27
Before we begin, note that this is an active area of language development in C as it works to get past some,
erm, growing pains. When C2x comes out, updates here are probable.
Most people are basically interested in the deceptively simple question, “How do I use such-and-such
character set in C?” We’ll get to that. But as we’ll see, it might already work on your system. Or you
might have to punt to a third-party library.
We’re going to talk about a lot of things this chapter—some are platform agnostic, and some are C-specific.
Let’s get an outline first of what we’re going to look at:
• Unicode background
• Character encoding background
• Source and Execution character Sets
• Using Unicode and UTF-8
• Using other character types like wchar_t, char16_t, and char32_t
Let’s dive in!
189
190 Chapter 27. Unicode, Wide Characters, and All That
Each code point represents a unique character. And each character has a unique numeric code point
associated with it.
For example, in Unicode, the numeric value 66 represents “B”, and 960 represents “π”. Other character
mappings that aren’t Unicode use different values, potentially, but let’s forget them and concentrate on
Unicode, the future!
So that’s one thing: there’s a number that represents each character. In Unicode, these numbers run from
0 to over 1 million.
Got it?
Because we’re about to flip the table a little.
27.3 Encoding
If you recall, an 8-bit byte can hold values from 0-255, inclusive. That’s great for “B” which is 66—that
fits in a byte. But “π” is 960, and that doesn’t fit in a byte! We need another byte. How do we store all
that in memory? Or what about bigger numbers, like 195,024? That’s going to need a number of bytes to
hold.
The Big Question: how are these numbers represented in memory? This is what we call the encoding of
the characters.
So we have two things: one is the code point which tells us effectively the serial number of a particular
character. And we have the encoding which tells us how we’re going to represent that number in memory.
There are plenty of encodings. You can make up your own right now, if you want1 . But we’re going to
look at some really common encodings that are in use with Unicode.
Encoding Description
UTF-8 A byte-oriented encoding that uses a variable number of bytes per character.
This is the one to use.
UTF-16 A 16-bit per character2 encoding.
UTF-32 A 32-bit per character encoding.
With UTF-16 and UTF-32, the byte order matters, so you might see UTF-16BE for big-endian and UTF-
16LE for little-endian. Same for UTF-32. Technically, if unspecified, you should assume big-endian. But
since Windows uses UTF-16 extensively and is little-endian, sometimes that is assumed3 .
Let’s look at some examples. I’m going to write the values in hex because that’s exactly two digits per
8-bit byte, and it makes it easier to see how things are arranged in memory.
Look in there for the patterns. Note that UTF-16BE and UTF-32BE are simply the code point represented
directly as 16- and 32-bit values4 .
1
For example, we could store the code point in a big-endian 32-bit integer. Straightforward! We just invented an encoding!
Actually not; that’s what UTF-32BE encoding is. Oh well—back to the grind!
2
Ish. Technically, it’s variable width—there’s a way to represent code points higher than 216 by putting two UTF-16 characters
together.
3
There’s a special character called the Byte Order Mark (BOM), code point 0xFEFF, that can optionally precede the data stream
and indicate the endianess. It is not required, however.
4
Again, this is only true in UTF-16 for characters that fit in two bytes.
27.4. Source and Execution Character Sets 191
Those are the characters you can use in your source and remain 100% portable.
The execution character set will additionally have characters for alert (bell/flash), backspace, carriage
return, and newline.
But most people don’t go to that extreme and freely use their extended character sets in source and exe-
cutable, especially now that Unicode and UTF-8 are getting more common. I mean, the basic character
set doesn’t even allow for @, $, or `!
Notably, it’s a pain (though possible with escape sequences) to enter Unicode characters using only the
basic character set.
27.5 Unicode in C
Before I get into encoding in C, let’s talk about Unicode from a code point standpoint. There is a way in
C to specify Unicode characters and these will get translated by the compiler into the execution character
5
https://en.wikipedia.org/wiki/UTF-8
6
https://www.youtube.com/watch?v=MijmeoH9LT4
192 Chapter 27. Unicode, Wide Characters, and All That
set7 .
So how do we do it?
How about the euro symbol, code point 0x20AC. (I’ve written it in hex because both ways of representing
it in C require hex.) How can we put that in our C code?
Use the \u escape to put it in a string, e.g. "\u20AC" (case for the hex doesn’t matter). You must put
exactly four hex digits after the \u, padding with leading zeros if necessary.
Here’s an example:
char *s = "\u20AC1.23";
So \u works for 16-bit Unicode code points, but what about ones bigger than 16 bits? For that, we need
capitals: \U.
For example:
char *s = "\U0001D4D1";
It’s the same as \u, just with 32 bits instead of 16. These are equivalent:
\u03C0
\U000003C0
Again, these are translated into the execution character set during compilation. They represent Unicode
code points, not any specific encoding. Furthermore, if a Unicode code point is not representable in the
execution character set, the compiler can do whatever it wants with it.
Now, you might wonder why you can’t just do this:
char *s = "€1.23";
And you probably can, given a modern compiler. The source character set will be translated for you into
the execution character set by the compiler. But compilers are free to puke out if they find any characters
that aren’t included in their extended character set, and the € symbol certainly isn’t in the basic character
set.
Caveat from the spec: you can’t use \u or \U to encode any code points below 0xA0 except for 0x24 ($),
0x40 (@), and 0x60 (`)—yes, those are precisely the trio of common punctuation marks missing from the
basic character set. Apparently this restriction is relaxed in the upcoming version of the spec.
Finally, you can also use these in identifiers in your code, with some restrictions. But I don’t want to get
into that here. We’re all about string handling in this chapter.
And that’s about it for Unicode in C (except encoding).
A lot of things will just work (albeit non-portably) because UTF-8 strings can safely be NUL-terminated
just like any other C string. But maybe losing portability in exchange for easier character handling is a
tradeoff that’s worth it to you.
There are some caveats, however:
• Things like strlen() report the number of bytes in a string, not the number of characters, neces-
sarily. (The mbstowcs() returns the number of characters in a string when you convert it to wide
characters. POSIX extends this so you can pass NULL for the first argument if you just want the
character count.)
• The following won’t work properly with characters of more than one byte: strtok(), strchr()
(use strstr() instead), strspn()-type functions, toupper(), tolower(), isalpha()-type
functions, and probably more. Beware anything that operates on bytes.
• printf() variants allow for a way to only print so many bytes of a string8 . You want to make
certain you print the correct number of bytes to end on a character boundary.
• If you want to malloc() space for a string, or declare an array of chars for one, be aware that the
maximum size could be more than you were expecting. Each character could take up to MB_LEN_MAX
bytes (from <limits.h>)—except characters in the basic character set which are guaranteed to be
one byte.
And probably others I haven’t discovered. Let me know what pitfalls there are out there…
What we’re saying here is that a particular character that’s not in the basic character set could be composed
of multiple bytes. Up to MB_LEN_MAX of them (from <limits.h>). Sure, it only looks like one character
on the screen, but it could be multiple bytes.
You can throw Unicode values in there, as well, as we saw earlier:
char *s = "\u20AC1.23";
But here we’re getting into some weirdness, because check this out:
char *s = "\u20AC1.23"; // €1.23
printf("%zu\n", strlen(s)); // 7!
8
With a format specifier like "%.12s", for example.
194 Chapter 27. Unicode, Wide Characters, and All That
The string length of "€1.23" is 7?! Yes! Well, on my system, yes! Remember that strlen() returns the
number of bytes in the string, not the number of characters. (When we get to “wide characters”, coming
up, we’ll see a way to get the number of characters in the string.)
Note that while C allows individual multibyte char constants (as opposed to char*), the behavior of these
varies by implementation and your compiler might warn on it.
GCC, for example, warns of multi-character character constants for the following two lines (and, on my
system, prints out the UTF-8 encoding):
printf("%x\n", '€');
printf("%x\n", '\u20ac');
Now—are those characters stored as Unicode code points, or not? Depends on the implementation. But
you can test if they are with the macro __STDC_ISO_10646__. If this is defined, the answer is, “It’s
Unicode!”
More detailedly, the value in that macro is an integer in the form yyyymm that lets you know what Unicode
standard you can rely on—whatever was in effect on that date.
But how do you use them?
27.8. Using Wide Characters and wchar_t 195
So if we want to convert a multibyte string to a wide character string, we can call the mbstowcs(). And
the other way around: wcstombs().
Let’s do a quick demo where we convert a multibyte string to a wide character string, and compare the
string lengths of the two using their respective functions.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <wchar.h>
4 #include <string.h>
5 #include <locale.h>
6
7 int main(void)
8 {
9 // Get out of the C locale to one that likely has the euro symbol
10 setlocale(LC_ALL, "");
11
19 // Convert the MB string to WC; this returns the number of wide chars
20 size_t wc_len = mbstowcs(wc_string, mb_string, 128);
21
(Your system might vary on the number of bytes depending on your locale.)
One interesting thing to note is that mbstowcs(), in addition to converting the multibyte string to wide,
returns the length (in characters) of the wide character string. On POSIX-compliant systems, you can take
advantage of a special mode where it only returns the length-in-characters of a given multibyte string: you
196 Chapter 27. Unicode, Wide Characters, and All That
just pass NULL to the destination, and 0 to the maximum number of characters to convert (this value is
ignored).
(In the code below, I’m using my extended source character set—you might have to replace those with \u
escapes.)
setlocale(LC_ALL, "");
printf("%zu", len_in_chars); // 7
27.9.1 wint_t
A lot of these functions use a wint_t to hold single characters, whether they are passed in or returned.
It is related to wchar_t in nature. A wint_t is an integer that can represent all values in the extended
character set, and also a special end-of-file character, WEOF.
This is used by a number of single-character-oriented wide character functions.
Copying
Func-
tion Description
wcscpy() Copy string.
wcsncpy()Copy string, length-limited.
wmemcpy()Copy memory.
Copy potentially-overlapping memory.
wmemmove()
wcscat() Concatenate strings.
wcsncat()Concatenate strings, length-limited.
9
wcscoll() is the same as wcsxfrm() followed by wcscmp().
27.10. Parse State, Restartable Functions 199
Here is a list of the restartable conversion functions—note the naming convension of putting an “r” after
the “from” type:
• mbrtowc()—multibyte to wide character
• wcrtomb()—wide character to multibyte
• mbsrtowcs()—multibyte string to wide character string
• wcsrtombs()—wide character string to multibyte string
These are really similar to their non-restartable counterparts, except they require you pass in a pointer to
your own mbstate_t variable. And also they modify the source string pointer (to help you out if invalid
bytes are found), so it might be useful to save a copy of the original.
Here’s the example from earlier in the chapter reworked to pass in our own mbstate_t.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stddef.h>
4 #include <wchar.h>
5 #include <string.h>
6 #include <locale.h>
7
8 int main(void)
9 {
10 // Get out of the C locale to one that likely has the euro symbol
11 setlocale(LC_ALL, "");
12
33 // Convert the MB string to WC; this returns the number of wide chars
34 size_t wc_len = mbsrtowcs(wc_string, &invalid, 128, &mbs);
35
36 if (invalid == NULL) {
37 printf("No invalid characters found\n");
38
For the conversion functions that manage their own state, you can reset their internal state to the initial
one by passing in NULL for their char* arguments, for example:
mbstowcs(NULL, NULL, 0); // Reset the parse state for mbstowcs()
mbstowcs(dest, src, 100); // Parse some stuff
For I/O, each wide stream manages its own mbstate_t and uses that for input and output conversions as
it goes.
And some of the byte-oriented I/O functions like printf() and scanf() keep their own internal state
while doing their work.
Finally, these restartable conversion functions do actually have their own internal state if you pass in NULL
for the mbstate_t parameter. This makes them behave more like their non-restartable counterparts.
27.11.1 UTF-8
To refresh before this section, read the UTF-8 quick note, above.
Aside from that, what are C’s UTF-8 capabilities?
Well, not much, unfortunately.
You can tell C that you specifically want a string literal to be UTF-8 encoded, and it’ll do it for you. You
can prefix a string with u8:
27.11. Unicode Encodings and C 201
Sure! If the extended source character set supports it. (gcc does.)
What if it doesn’t? You can specify a Unicode code point with your friendly neighborhood \u and \U, as
noted above.
But that’s about it. There’s no portable way in the standard library to take arbirary input and turn it into
UTF-8 unless your locale is UTF-8. Or to parse UTF-8 unless your locale is UTF-8.
So if you want to do it, either be in a UTF-8 locale and:
setlocale(LC_ALL, "");
or figure out a UTF-8 locale name on your local machine and set it explicitly like so:
setlocale(LC_ALL, "en_US.UTF-8"); // Non-portable name
#if __STDC_UTF_16__
pi == 0x3C0; // Always true
202 Chapter 27. Unicode, Wide Characters, and All That
#else
pi == 0x3C0; // Probably not true
#endif
All of these functions are restartable (i.e. you pass in your own mbstate_t), and all of them operate
character by character10 .
10
Ish—things get funky with multi-char16_t UTF-16 encodings.
11
https://en.wikipedia.org/wiki/Iconv
12
http://site.icu-project.org/
Chapter 28
Exiting a Program
Turns out there are a lot of ways to do this, and even ways to set up “hooks” so that a function runs when
a program exits.
In this chapter we’ll dive in and check them out.
We already covered the meaning of the exit status code in the Exit Status section, so jump back there and
review if you have to.
All the functions in this section are in <stdlib.h>.
28.1.2 exit()
This one has also made an appearance a few times. If you call exit() from anywhere in your program,
it will exit at that point.
The argument you pass to exit() is the exit status.
203
204 Chapter 28. Exiting a Program
4 void on_exit_1(void)
5 {
6 printf("Exit handler 1 called!\n");
7 }
8
9 void on_exit_2(void)
10 {
11 printf("Exit handler 2 called!\n");
12 }
13
14 int main(void)
15 {
16 atexit(on_exit_1);
17 atexit(on_exit_2);
18
19 printf("About to exit...\n");
20 }
4 void on_quick_exit_1(void)
5 {
6 printf("Quick exit handler 1 called!\n");
7 }
8
9 void on_quick_exit_2(void)
10 {
11 printf("Quick exit handler 2 called!\n");
12 }
13
14 void on_exit(void)
28.3. Nuke it from Orbit: _Exit() 205
15 {
16 printf("Normal exit--I won't be called!\n");
17 }
18
19 int main(void)
20 {
21 at_quick_exit(on_quick_exit_1);
22 at_quick_exit(on_quick_exit_2);
23
28 quick_exit(0);
29 }
It works just like exit()/atexit(), except for the fact that file flushing and cleanup might not be done.
versus:
goats -= 100;
In that case, if I try to run it and goats falls under 0, this happens:
goat_counter: goat_counter.c:8: main: Assertion `goats >= 0' failed.
Aborted
1
https://en.wikipedia.org/wiki/Core_dump
Chapter 29
Signal Handling
Before we start, I’m just going to advise you to generally ignore this entire chapter and use your OS’s
(very likely) superior signal handling functions. Unix-likes have the sigaction() family of functions,
and Windows has… whatever it does1 .
With that out of the way, what are signals?
Signal Description
SIGABRT Abnormal termination—what happens when
abort() is called.
SIGFPE Floating point exception.
SIGILL Illegal instruction.
SIGINT Interrupt—usually the result of CTRL-C being hit.
SIGSEGV “Segmentation Violation”: invalid memory access.
SIGTERM Termination requested.
You can set up your program to ignore, handle, or allow the default action for each of these by using the
signal() function.
207
208 Chapter 29. Signal Handling
1 #include <stdio.h>
2 #include <signal.h>
3
4 int main(void)
5 {
6 char s[1024];
7
Check out line 8—we tell the program to ignore SIGINT, the interrupt signal that’s raised when CTRL-C
is hit. No matter how much you hit it, the signal remains ignored. If you comment out line 8, you’ll see
you can CTRL-C with impunity and quit the program on the spot.
Basically, we’re going to pass in the signal number we’re interested in catching, and we’re going to pass
a pointer to a function of the form:
void f(int x);
I want to be clear that this program engages in undefined behavior in a couple ways. But it’ll probably
work for you, and it’s hard to come up with portable non-trivial demos.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <signal.h>
4
5 int count = 0;
6
21 if (count == 2) {
22 printf("Exiting!\n"); // Undefined behavior
23 exit(0);
24 }
25 }
26
27 int main(void)
28 {
29 signal(SIGINT, sigint_handler);
30
One of the things you’ll notice is that on line 14 we reset the signal handler. This is because C has the
option of resetting the signal handler to its SIG_DFL behavior before running your custom handler. In
other words, it could be a one-off. So we reset it first thing so that we handle it again for the next one.
We’re ignoring the return value from signal() in this case. If we’d set it to a different handler earlier, it
would return a pointer to that handler, which we could get like this:
// old_handler is type "pointer to function that takes a single
// int parameter and returns void":
void (*old_handler)(int);
That said, I’m not sure of a common use case for this. But if you need the old handler for some reason,
you can get it that way.
Quick note on line 16—that’s just to tell the compiler to not warn that we’re not using this variable. It’s
like saying, “I know I’m not using it; you don’t have to warn me.”
And lastly you’ll see that I’ve marked undefined behavior in a couple places. More on that in the next
section.
210 Chapter 29. Signal Handling
Confusingly, the spec also says you can’t refer “to any object with static or thread storage duration
that is not a lock-free atomic object other than by assigning a value to an object declared as volatile
sig_atomic_t […]”
My read on this is that you can’t read or write anything that’s not a lock-free atomic object. Also you can
assign to an object that’s volatile sig_atomic_t.
But can you read from it? I honestly don’t see why not, except that the spec is very pointed about men-
tioning assigning into. But if you have to read it and make any kind of decision based on it, you might be
opening up room for some kind of race conditions.
With that in mind, we can rewrite our “hit CTRL-C twice to exit” code to be a little more portable, albeit
less verbose on the output.
Let’s change our SIGINT handler to do nothing except increment a value that’s of type volatile
sig_atomic_t. So it’ll count the number of CTRL-Cs that have been hit.
Then in our main loop, we’ll check to see if that counter is over 2, then bail out if it is.
1 #include <stdio.h>
2 #include <signal.h>
3
15 int main(void)
16 {
17 signal(SIGINT, sigint_handler);
2
Confusingly, sig_atomic_t predates the lock-free atomics and is not the same thing.
3
If sig_action_t is signed, the range will be at least -127 to 127. If unsigned, at least 0 to 255.
29.5. Friends Don’t Let Friends signal() 211
18
Undefined behavior again? It’s my read that this is, because we have to read the value in order to increment
and store it.
If we only want to postpone the exit by one hitting of CTRL-C, we can do that without too much trouble.
But any more postponement would require some ridiculous function chaining.
What we’ll do is handle it once, and the handler will reset the signal to its default behavior (that is, to
exit):
1 #include <stdio.h>
2 #include <signal.h>
3
10 int main(void)
11 {
12 signal(SIGINT, sigint_handler);
13
16 while(1);
17 }
Later when we look at lock-free atomic variables, we’ll see a way to fix the count version (assuming
lock-free atomic variables are available on your particular system).
This is why at the beginning, I was suggesting checking out your OS’s built-in signal system as a probably-
superior alternative.
C provides a way for you to declare an array whose size is determined at runtime. This gives you the
benefits of dynamic runtime sizing like you get with malloc(), but without needing to worry about
free()ing the memory after.
Now, a lot of people don’t like VLAs. They’ve been banned from the Linux kernel, for example. We’ll
dig into more of that rationale later.
This is an optional feature of the language. The macro __STDC_NO_VLA__ is set to 1 if VLAs are not
present. (They were mandatory in C99, and then became optional in C11.)
#if __STDC_NO_VLA__ == 1
#error Sorry, need VLAs for this program!
#endif
But since neither GCC nor Clang bother to define this macro, you may get limited mileage from this.
Let’s dive in first with an example, and then we’ll look for the devil in the details.
But with VLAs, we can use a size determined at runtime to set the array, like this:
int n = 10;
int v[n];
Now, that looks like the same thing, and in many ways is, but this gives you the flexibility to compute the
size you need, and then get an array of exactly that size.
Let’s ask the user to input the size of the array, and then store the index-times-10 in each of those array
elements:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int n;
6
10 int v[n];
11
213
214 Chapter 30. Variable-Length Arrays (VLAs)
(On line 7, I have an fflush() that should force the line to output even though I don’t have a newline at
the end.)
Line 10 is where we declare the VLA—once execution gets past that line, the size of the array is set to
whatever n was at that moment. The array length can’t be changed later.
You can put an expression in the brackets, as well:
int v[x * 100];
Some restrictions:
• You can’t declare a VLA at file scope, and you can’t make a static one in block scope1 .
• You can’t use an initializer list to initialize the array.
Also, entering a negative value for the size of the array invokes undefined behavior—in this universe,
anyway.
There’s a subtle and correct implication from the above line: pointer arithmetic works just like you’d
expect for a regular array. So go ahead and use it to your heart’s content:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int n = 5;
6 int v[n];
7
8 int *p = v;
9
10 *(p+2) = 12;
11 printf("%d\n", v[2]); // 12
12
13 p[3] = 34;
14 printf("%d\n", v[3]); // 34
15 }
Like with regular arrays, you can use parentheses with sizeof() to get the size of a would-be VLA
without actually declaring one:
1
This is due to how VLAs are typically allocated on the stack, whereas static variables are on the heap. And the whole idea
with VLAs is they’ll be automatically dellocated when the stack frame is popped at the end of the function.
30.3. Multidimensional VLAs 215
int x = 12;
int x[h][w];
int y[5][w];
int z[10][w][20];
Again, you can navigate these just like you would a regular array.
10 return total;
11 }
12
13 int main(void)
14 {
15 int x[5]; // Standard array
16
17 int a = 5;
18 int y[a]; // VLA
19
But there’s a bit more to it than that. You can also let C know that the array is a specific VLA size by
passing that in first and then giving that dimension in the parameter list:
int sum(int count, int v[count])
{
// ...
}
Incidentally, there are a couple ways of listing a prototype for the above function; one of them involves
an * if you don’t want to specifically name the value in the VLA. It just indicates that the type is a VLA
as opposed to a regular pointer.
216 Chapter 30. Variable-Length Arrays (VLAs)
VLA prototypes:
void do_something(int count, int v[count]); // With names
void do_something(int, int v[*]); // Without names
Again, that * thing only works with the prototype—in the function itself, you’ll have to put the explicit
size.
Now—let’s get multidimensional! This is where the fun begins.
12 int main(void)
13 {
14 int rows = 4;
15 int cols = 7;
16
17 int matrix[rows][cols];
18
12 int main(void)
30.6. Compatibility with Regular Arrays 217
13 {
14 int rec_count = 3;
15 int records[rec_count][5];
16
22 print_records(rec_count, records);
23 }
\\ ...
int w = 3, h = 5;
int matrix[h][w];
foo(matrix); // OK!
Likewise, if you have a VLA function, you can pass a regular array into it:
int foo(int h, int w, int m[h][w]) {...}
\\ ...
int matrix[3][5];
Beware, though: if your dimensions mismatch, you’re going to have some undefined behavior going on,
likely.
3 int main(void)
4 {
5 int w = 10;
6
11
16 // Print them
17 for (int i = 0; i < w; i++)
18 printf("%d\n", x[i]);
19
22 w = 20;
23
goto
The goto statement is universally revered and can be here presented without contest.
Just kidding! Over the years, there has been a lot of back-and-forth over whether or not (often not) goto
is considered harmful1 .
In this programmer’s opinion, you should use whichever constructs leads to the best code, factoring in
maintainability and speed. And sometimes this might be goto!
In this chapter, we’ll see how goto works in C, and then check out some of the common cases where it is
used2 .
3 int main(void)
4 {
5 printf("One\n");
6 printf("Two\n");
7
8 goto skip_3;
9
10 printf("Three\n");
11
12 skip_3:
13
14 printf("Five!\n");
15 }
goto sends execution jumping to the specified label, skipping everything in between.
219
220 Chapter 31. goto
infinite_loop:
print("Hello, world!\n");
goto infinite_loop;
Labels are skipped over during execution. The following will print all three numbers in order just as if
the labels weren’t there:
printf("Zero\n");
label_1:
label_2:
printf("One\n");
label_3:
printf("Two\n");
label_4:
printf("Three\n");
As you’ve noticed, it’s common convention to justify the labels all the way on the left. This increases
readability because a reader can quickly scan to find the destination.
Labels have function scope. That is, no matter how many levels deep in blocks they appear, you can still
goto them from anywhere in the function.
It also means you can only goto labels that are in the same function as the goto itself. Labels in other
functions are out of scope from goto’s perspective. And it means you can use the same label name in two
functions—just not the same label name in the same function.
As we see, that continue, like all continues, goes to the next iteration of the nearest enclosing loop.
What if we want to continue in the next loop out, the loop with i?
Well, we can break to get back to the outer loop, right?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d, %d\n", i, j);
break; // Gets us to the next iteration of i
}
}
That gets us two levels of nested loop. But then if we nest another loop, we’re out of options. What about
this, where we don’t have any statement that will get us out to the next iteration of i?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
printf("%d, %d, %d\n", i, j, k);
}
}
}
We have a ; at the end there—that’s because you can’t have a label pointing to the plain end of a compound
statement (or before a variable declaration).
for(...) {
for (...) {
while (...) {
do {
if (some_error_condition)
goto bail;
} while(...);
}
}
}
bail:
// Cleanup here
Without goto, you’d have to check an error condition flag in all of the loops to get all the way out.
printf("Done!\n");
222 Chapter 31. goto
break_i:
printf("Done!\n");
Let’s do a fake example where we start initializing systems and checking to see if any returns an error
(we’ll use -1 to indicate an error). If one of them does, we have to shutdown only the systems we’ve
initialized so far.
if (init_system_1() == -1)
goto shutdown;
if (init_system_2() == -1)
goto shutdown_1;
if (init_system_3() == -1)
goto shutdown_2;
if (init_system_4() == -1)
goto shutdown_3;
shutdown_system4();
shutdown_3:
shutdown_system3();
shutdown_2:
shutdown_system2();
shutdown_1:
shutdown_system1();
shutdown:
print("All subsystems shut down.\n");
Note that we’re shutting down in the reverse order that we initialized the subsystems. So if subsystem 4
fails to start up, it will shut down 3, 2, then 1 in that order.
If you’re unfamiliar, Tail Call Optimization (TCO)3 is a way to not waste stack space when calling other
functions under very specific circumstances. Unfortunately the details are beyond the scope of this guide.
But if you have a recursive function you know can be optimized in this way, you can make use of this
technique. (Note that you can’t tail call other functions due to the function scope of labels.)
Let’s do a straightforward example, factorial.
Here’s a recursive version that’s not TCO, but it can be!
1 #include <stdio.h>
2 #include <complex.h>
3
12 int main(void)
13 {
14 for (int i = 0; i < 8; i++)
15 printf("%d! == %ld\n", i, factorial(i, 1));
16 }
To make it happen, you can replace the call with two steps:
1. Set the values of the parameters to what they’d be on the next call.
2. goto a label on the first line of the function.
Let’s try it:
1 #include <stdio.h>
2
7 if (n == 0)
8 return a;
9
24 int main(void)
25 {
26 for (int i = 0; i < 8; i++)
3
https://en.wikipedia.org/wiki/Tail_call
224 Chapter 31. goto
I used temporary variables up there to set the next values of the parameters before jumping to the start of
the function. See how they correspond to the recursive arguments that were in the recursive call?
Now, why use temp variables? I could have done this instead:
a *= n;
n -= 1;
goto tco;
and that actually works just fine. But if I carelessly reverse those two lines of code:
n -= 1; // BAD NEWS
a *= n;
—now we’re in trouble. We modified n before using it to modify a. That’s Bad because that’s not how
it works when you call recursively. Using the temporary variables avoids this problem even if you’re not
looking out for it. And the compiler likely optimizes them out, anyway.
Many Unix-likes have an SA_RESTART flag you can pass to sigaction() to request the OS automatically
restart any slow syscalls instead of failing with EINTR.
Again, this is Unix-specific and is outside the C standard.
That said, it’s possible to use a similar technique any time any function should be restarted.
{
int x = 12345;
label:
printf("%d\n", x);
}
31.9. goto and Variable-Length Arrays 225
And then it prints out 0 when I run it (your mileage may vary).
Basically what has happened is that we jumped into x’s scope (so it was OK to reference it in the printf())
but we jumped over the line that actually initialized it to 12345. So the value was indeterminate.
The fix is, of course, to get the initialization after the label one way or another.
goto label;
{
int x;
label:
x = 12345;
printf("%d\n", x);
}
label:
printf("%d\n", x);
}
goto label;
goto label;
{
int v[x];
label:
printf("Hi!\n");
}
226 Chapter 31. goto
I get an error:
error: jump into scope of identifier with variably modified type
goto label;
{
label: ;
int v[x];
printf("Hi!\n");
}
Because that way the VLA gets allocated properly before its inevitable deallocation once it falls out of
scope.
Chapter 32
This is the final chapter for types! We’re going to talk about two things:
• How to have “anonymous” unnamed objects and how that’s useful.
• How to generate type-dependent code.
They’re not particularly related, but don’t really each warrant their own chapters. So I crammed them in
here like a rebel!
Now, that line of code doesn’t do anything on its own. It creates an unnamed array of 4 ints, and then
throws them away without using them.
We could use a pointer to store a reference to the array…
int *p = (int []){1 ,2 ,3 ,4};
printf("%d\n", p[1]); // 2
But that seems a little like a long-winded way to have an array. I mean, we could have just done this1 :
int p[] = {1, 2, 3, 4};
printf("%d\n", p[1]); // 2
227
228 Chapter 32. Types Part V: Compound Literals and Generic Selections
return total;
}
If we wanted to call it, we’d normally have to do something like this, declaring an array and storing values
in it to pass to the function:
int a[] = {1, 2, 3, 4};
But unnamed objects give us a way to skip the variable by passing it directly in (parameter names listed
above). Check it out—we’re going to replace the variable a with an unnamed array that we pass in as the
first argument:
// p[] count
// |-----------------| |
int s = sum((int []){1, 2, 3, 4}, 4);
Pretty slick!
3 struct coord {
4 int x, y;
5 };
6
12 int main(void)
13 {
14 struct coord t = {.x=10, .y=20};
15
Straightforward enough?
Let’s modify it to use an unnamed object instead of the variable t we’re passing to print_coord().
We’ll just take t out of there and replace it with an unnamed struct:
7 //struct coord t = {.x=10, .y=20};
8
Still works!
32.1. Compound Literals 229
3 struct coord {
4 int x, y;
5 };
6
12 int main(void)
13 {
14 // Note the &
15 // |
16 print_coord(&(struct coord){.x=10, .y=20}); // prints "10, 20"
17 }
Additionally, this can be a nice way to pass even pointers to simple objects:
// Pass a pointer to an int with value 3490
foo(&(int){3490});
Easy as that.
{
p = &(int){10};
}
Likewise, you can’t return a pointer to an unnamed object from a function. The object is deallocated when
it falls out of scope:
1 #include <stdio.h>
2
3 int *get3490(void)
4 {
5 // Don't do this
6 return &(int){3490};
7 }
230 Chapter 32. Types Part V: Compound Literals and Generic Selections
9 int main(void)
10 {
11 printf("%d\n", *get3490()); // INVALID: (int){3490} fell out of scope
12 }
Just think of their scope like that of an ordinary local variable. You can’t return a pointer to a local variable,
either.
That last one is unnamed, but it’s silly. Might as well do the simple one on the line before.
But hopefully that provides a little more clarity on the syntax.
3 int main(void)
4 {
5 int i;
6 float f;
7 char c;
8
9 char *s = _Generic(i,
10 int: "that variable is an int",
11 float: "that variable is a float",
12 default: "that variable is some type"
13 );
14
15 printf("%s\n", s);
16 }
When the compiler sees it, it looks at the type of the first argument. (In this example, the type of the variable
i.) It then looks through the cases for something of that type. And then it substitutes the argument in place
of the entire _Generic expression.
In this case, i is an int, so it matches that case. Then the string is substituted in for the expression. So
the line turns into this when the compiler sees it:
char *s = "that variable is an int";
If the compiler can’t find a type match in the _Generic, it looks for the optional default case and uses
that.
If it can’t find a type match and there’s no default, you’ll get a compile error. The first expression must
match one of the types or default.
Because it’s inconvenient to write _Generic over and over, it’s often used to make the body of a macro
that can be easily repeatedly reused.
Let’s make a macro TYPESTR(x) that takes an argument and returns a string with the type of the argument.
So TYPESTR(1) will return the string "int", for example.
Here we go:
#include <stdio.h>
int main(void)
{
int i;
long l;
float f;
double d;
char c;
This outputs:
i is type int
l is type long
f is type float
d is type double
c is type something else
Which should be no surprise, because, like we said, that code in main() is replaced with the following
when it is compiled:
printf("i is type %s\n", "int");
printf("l is type %s\n", "long");
printf("f is type %s\n", "float");
printf("d is type %s\n", "double");
printf("c is type %s\n", "something else");
232 Chapter 32. Types Part V: Compound Literals and Generic Selections
PRINT_VAL(i);
PRINT_VAL(s);
20 int main(void)
21 {
22 int i = 10;
23 float f = 3.14159;
24 char *s = "Hello, world!";
25
26 PRINT_VAL(i);
27 PRINT_VAL(f);
28 PRINT_VAL(s);
29 }
We could have crammed that all in one big macro, but I broke it into two to prevent eye bleeding.
Chapter 33
Arrays Part II
We’re going to go over a few extra misc things this chapter concerning arrays.
• Type qualifiers with array parameters
• The static keyword with array parameters
• Partial multi-dimensional array initializers
They’re not super-commonly seen, but we’ll peek at them since they’re part of the newer spec.
And you might also recall that you can add type qualifiers to a pointer variable like so:
int *const p;
int *volatile p;
int *const volatile p;
// etc.
But how can we do that when we’re using array notation in your parameter list?
Turns out it goes in the brackets. And you can put the optional count after. The two following lines are
equivalent:
int func(int *const volatile p) {...}
int func(int p[const volatile]) {...}
int func(int p[const volatile 10]) {...}
If you have a multidimensional array, you need to put the type qualifiers in the first set of brackets.
What this means, in the above example, is the compiler is going to assume that any array you pass to the
function will be at least 4 elements.
Anything else is undefined behavior.
233
234 Chapter 33. Arrays Part II
int main(void)
{
int a[] = {11, 22, 33, 44};
int b[] = {11, 22, 33, 44, 55};
int c[] = {11, 22};
This basically sets the minimum size array you can have.
Important note: there is nothing in the compiler that prohibits you from passing in a smaller array. The
compiler probably won’t warn you, and it won’t detect it at runtime.
By putting static in there, you’re saying, “I double secret PROMISE that I will never pass in a smaller
array than this.” And the compiler says, “Yeah, fine,” and trusts you to not do it.
And then the compiler can make certain code optimizations, safe in the knowledge that you, the program-
mer, will always do the right thing.
int main(void)
{
int a[3][2] = {
{1, 2},
{3, 4},
{5, 6}
};
1 2
3 4
5 6
Let’s leave off some of the initializer elements and see they get set to zero:
int a[3][2] = {
{1, 2},
{3}, // Left off the 4!
{5, 6}
};
which produces:
1 2
3 0
5 6
And now we get this, which might not be what you expect:
1 2
5 6
0 0
But if you stop to think about it, we only provided enough initializers for two rows, so they got used for
the first two rows. And the remaining elements were initialized to zero.
So far so good. Generally, if we leave off parts of the initializer, the compiler sets the corresponding
elements to 0.
But let’s get crazy.
int a[3][2] = { 1, 2, 3, 4, 5, 6 };
So if you want to fill the whole array with 0, then go ahead and:
int a[3][2] = {0};
236 Chapter 33. Arrays Part II
But my recommendation is if you have a 2D array, use a 2D initializer. It just makes the code more
readable. (Except for initializing the whole array with 0, in which case it’s idiomatic to use {0} no matter
the dimension of the array.)
Chapter 34
We’ve already seen goto, which jumps in function scope. But longjmp() allows you to jump back to an
earlier point in execution, back to a function that called this one.
There are a lot of limitations and caveats, but this can be a useful function for bailing out from deep in the
call stack back up to an earlier state.
In my experience, this is very rarely-used functionality.
4 jmp_buf env;
5
6 void depth2(void)
7 {
8 printf("Entering depth 2\n");
9 longjmp(env, 3490); // Bail out
10 printf("Leaving depth 2\n"); // This won't happen
11 }
12
13 void depth1(void)
14 {
15 printf("Entering depth 1\n");
16 depth2();
17 printf("Leaving depth 1\n"); // This won't happen
18 }
19
20 int main(void)
21 {
237
238 Chapter 34. Long Jumps with setjmp, longjmp
22 switch (setjmp(env)) {
23 case 0:
24 printf("Calling into functions, setjmp() returned 0\n");
25 depth1();
26 printf("Returned from functions\n"); // This won't happen
27 break;
28
29 case 3490:
30 printf("Bailed back to main, setjmp() returned 3490\n");
31 break;
32 }
33 }
If you try to take that output and match it up with the code, it’s clear there’s some really funky stuff going
on.
One of the most notable things is that setjmp() returns twice. What the actual frank? What is this
sorcery?!
So here’s the deal: if setjmp() returns 0, it means that you’ve successfully set the “bookmark” at that
point.
If it returns non-zero, it means you’ve just returned to the “bookmark” set earlier. (And the value returned
is the one you pass to longjmp().)
This way you can tell the difference between setting the bookmark and returning to it later.
So when the code, above, calls setjmp() the first time, setjmp() stores the state in the env variable and
returns 0. Later when we call longjmp() with that same env, it restores the state and setjmp() returns
the value longjmp() was passed.
34.2 Pitfalls
Under the hood, this is pretty straightforward. Typically the stack pointer keeps track of the locations
in memory that local variables are stored, and the program counter keeps track of the address of the
currently-executing instruction1 .
So if we want to jump back to an earlier function, it’s basically only a matter of restoring the stack pointer
and program counter to the values kept in the jmp_buf variable, and making sure the return value is set
correctly. And then execution will resume there.
But a variety of factors confound this, making a significant number of undefined behavior traps.
if (setjmp(env) == 0) {
x = 30;
}
if (setjmp(env) == 0) {
x = 30;
}
Now the value will be the correct 30 after a longjmp() returns us to this point.
That’s too complex to be allowed by the spec due to the machinations that must occur when unrolling
the stack and all that. We can’t longjmp() back into some complex expression that’s only been partially
executed.
So there are limits on the complexity of that expression.
• It can be the entire controlling expression of the conditional.
if (setjmp(env)) {...}
• It can be part of a relational or equality expression, as long as the other operand is an integer constant.
And the whole thing is the controlling expression of the conditional.
if (setjmp(env) == 0) {...}
• The operand to a logical NOT (!) operation, being the entire controlling expression.
if (!setjmp(env)) {...}
240 Chapter 34. Long Jumps with setjmp, longjmp
(void)setjmp(env);
3
That is, remain allocated until the program ends with no way to free it.
Chapter 35
Incomplete Types
int main(void)
{
struct foo *x;
union bar *y;
enum baz *z;
}
We never gave a size for a. And we have pointers to structs foo, bar, and baz that never seem to be
declared anywhere.
And the only warnings I get are that x, y, and z are unused.
These are examples of incomplete types.
An incomplete type is a type the size (i.e. the size you’d get back from sizeof) for which is not known.
Another way to think of it is a type that you haven’t finished declaring.
You can have a pointer to an incomplete type, but you can’t dereference it or use pointer arithmetic on it.
And you can’t sizeof it.
So what can you do with it?
241
242 Chapter 35. Incomplete Types
But what if we’re doing a linked list? Each linked list node needs to have a reference to another node. But
how can we create a reference to another node if we haven’t finished even declaring the node yet?
C’s allowance for incomplete types makes it possible. We can’t declare a node, but we can declare a
pointer to one, even if it’s incomplete!
struct node {
int val;
struct node *next; // struct node is incomplete, but that's OK!
};
Even though the struct node is incomplete on line 3, we can still declare a pointer to one1 .
We can do the same thing if we have two different structs that refer to each other:
struct a {
struct b *x; // Refers to a `struct b`
};
struct b {
struct a *x; // Refers to a `struct a`
};
We’d never be able to make that pair of structures without the relaxed rules for incomplete types.
Most likely culprit: you probably forgot to #include the header file that declares the type.
If it’s a non-extern array with no size followed by an initializer, it’s incomplete until the closing brace
of the initializer.
1 // File: bar.h
2
3 #ifndef BAR_H
4 #define BAR_H
5
8 #endif
Then you can include the header from as many places as you’d like, and every one of those places will
refer to the same underlying my_array.
1 // File: foo.c
2
3 #include <stdio.h>
4 #include "bar.h" // includes the incomplete type for my_array
5
6 int main(void)
7 {
8 my_array[0] = 10;
9
10 printf("%d\n", my_array[0]);
11 }
When compiling multiple files, remember to specify all the .c files to the compiler, but not the .h files,
e.g.:
gcc -o foo foo.c bar.c
struct foo {
int x, y, z;
}; // Now the struct foo is complete!
Note that though void is an incomplete type, there’s no way to complete it. Not that anyone ever thinks
of doing that weird thing. But it does explain why you can do this:
void *p; // OK: pointer to incomplete type
Complex Numbers
Furthermore, there is a macro that indicates adherence to the ISO 60559 (IEEE 754) standard for floating
point math with complex numbers, as well as the presence of the _Imaginary type.
#if __STDC_IEC_559_COMPLEX__ != 1
#error Need IEC 60559 complex support!
#endif
More details on that are spelled out in Annex G in the C11 spec.
Those both mean the same thing, so you might as well use the prettier complex.
You also get some types for imaginary numbers if you implementation is IEC 60559-compliant:
_Imaginary
imaginary
1
https://en.wikipedia.org/wiki/Complex_number
245
246 Chapter 36. Complex Numbers
These also both mean the same thing, so you might as well use the prettier imaginary.
The macro I is set to _Imaginary_I (if available), or _Complex_I. So just use I for the imaginary
number.
One aside: I’ve said that if a compiler has __STDC_IEC_559_COMPLEX__ set to 1, it must support _Imag-
inary types to be compliant. That’s my read of the spec. However, I don’t know of a single compiler that
actually supports _Imaginary even though they have __STDC_IEC_559_COMPLEX__ set. So I’m going
to write some code with that type in here I have no way of testing. Sorry!
OK, so now we know there’s a complex type, how can we use it?
We do that by just pinning a float, double, or long double to the complex, either before or after it.
Let’s define a complex number that uses float for its components:
float complex c; // Spec prefers this way
complex float c; // Same thing--order doesn't matter
So that’s great for declarations, but how do we initialize them or assign to them?
There’s also no problem using other floating point numbers to build it:
double a = 5;
double b = 2;
double complex x = a + b*I;
There is also a set of macros to help build these. The above code could be written using the CMPLX()
macro, like so:
double complex x = CMPLX(5, 2);
But the CMPLX() macro will handle negative zeros in the imaginary part correctly every time, whereas
the other way might convert them to positive zeros. I think2 This seems to imply that if there’s a chance
the imaginary part will be zero, you should use the macro… but someone should correct me on this if I’m
mistaken!
The CMPLX() macro works on double types. There are two other macros for float and long double:
CMPLXF() and CMPLXL(). (These “f” and “l” suffixes appear in virtually all the complex-number-related
functions.)
Now let’s try the reverse: if we have a complex number, how do we break it apart into its real and imaginary
parts?
Here we have a couple functions that will extract the real and imaginary parts from the number: creal()
and cimag():
double complex x = 5 + 2*I;
double complex y = 10 + 3*I;
Note that the i I have in the printf() format string is a literal i that gets printed—it’s not part of the
format specifier. Both return values from creal() and cimag() are double.
And as usual, there are float and long double variants of these functions: crealf(), cimagf(),
creall(), and cimagl().
4 int main(void)
5 {
6 double complex x = 1 + 2*I;
7 double complex y = 3 + 4*I;
8 double complex z;
9
10 z = x + y;
11 printf("x + y = %f + %fi\n", creal(z), cimag(z));
12
13 z = x - y;
14 printf("x - y = %f + %fi\n", creal(z), cimag(z));
15
16 z = x * y;
17 printf("x * y = %f + %fi\n", creal(z), cimag(z));
18
19 z = x / y;
2
This was a harder one to research, and I’ll take any more information anyone can give me. I could be defined as _Complex_I
or _Imaginary_I, if the latter exists. _Imaginary_I will handle signed zeros, but _Complex_I might not. This has implications
with branch cuts and other complex-numbery-mathy things. Maybe. Can you tell I’m really getting out of my element here? In any
case, the CMPLX() macros behave as if I were defined as _Imaginary_I, with signed zeros, even if _Imaginary_I doesn’t exist
on the system.
248 Chapter 36. Complex Numbers
You can also compare two complex numbers for equality (or inequality):
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2*I;
7 double complex y = 3 + 4*I;
8
They are equal if both components test equal. Note that as with all floating point, they could be equal if
they’re close enough due to rounding error3 .
Function Description
ccos() Cosine
csin() Sine
ctan() Tangent
cacos() Arc cosine
casin() Arc sine
catan() Play Settlers of Catan
ccosh() Hyperbolic cosine
csinh() Hyperbolic sine
ctanh() Hyperbolic tangent
cacosh() Arc hyperbolic cosine
3
The simplicity of this statement doesn’t do justice to the incredible amount of work that goes into simply understanding how
floating point actually functions. https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
36.5. Complex Math 249
Function Description
casinh() Arc hyperbolic sine
catanh() Arc hyperbolic tangent
Function Description
cexp() Base-𝑒 exponential
clog() Natural (base-𝑒) logarithm
Function Description
cabs() Absolute value
cpow() Power
csqrt() Square root
Function Description
creal() Return real part
cimag() Return imaginary part
CMPLX() Construct a complex number
carg() Argument/phase angle
conj() Conjugate4
cproj() Projection on Riemann sphere
4
This is the only one that doesn’t begin with an extra leading c, strangely.
250 Chapter 36. Complex Numbers
Chapter 37
C has all those small, bigger, and biggest integer types like int and long and all that. And you can look
in the section on limits to see what the largest int is with INT_MAX and so on.
How big are those types? That is, how many bytes do they take up? We could use sizeof to get that
answer.
But what if I wanted to go the other way? What if I needed a type that was exactly 32 bits (4 bytes) or at
least 16 bits or somesuch?
How can we declare a type that’s a certain size?
The header <stdint.h> gives us a way.
251
252 Chapter 37. Fixed Width Integer Types
int_least8_t uint_least8_t
int_least16_t uint_least16_t
int_least32_t uint_least32_t
int_least64_t uint_least64_t
int_fast8_t uint_fast8_t
int_fast16_t uint_fast16_t
int_fast32_t uint_fast32_t
int_fast64_t uint_fast64_t
There might be others of different widths, as well, but those are optional.
Hey! Where are the fixed types like int16_t? Turns out those are entirely optional…unless certain con-
ditions are met2 . And if you have an average run-of-the-mill modern computer system, those conditions
probably are met. And if they are, you’ll have these types:
int8_t uint8_t
int16_t uint16_t
int32_t uint32_t
int64_t uint64_t
Other variants with different widths might be defined, but they’re optional.
2
Namely, the system has 8, 16, 32, or 64 bit integers with no padding that use two’s complement representation, in which case
the intN_t variant for that particular number of bits must be defined.
37.5. Format Specifiers 253
Note the MIN for all the unsigned types is 0, so, as such, there’s no macro for it.
Look for the patterns there. You can see there are variants for the fixed, least, fast, and max types.
And you also have a lowercase d and a lowercase i. Those correspond to the printf() format specifiers
%d and %i.
I can print that with the equivalent format specifier for %d by using PRId16.
But how? How do we use that macro?
First of all, that macro specifies a string containing the letter or letters printf() needs to use to print that
type. Like, for example, it could be "d" or "ld".
So all we need to do is embed that in our format string to the printf() call.
To do this, we can take advantage of a fact about C that you might have forgotten: adjacent string literals
are automatically concatenated to a single string. E.g.:
printf("Hello, " "world!\n"); // Prints "Hello, world!"
And since these macros are string literals, we can use them like so:
1 #include <stdio.h>
2 #include <stdint.h>
254 Chapter 37. Fixed Width Integer Types
3 #include <inttypes.h>
4
5 int main(void)
6 {
7 int_least16_t x = 3490;
8
Remember: when you want to print out a fixed size integer type with printf() or scanf(), grab the
correct corresponding format specifer from <inttypes.h>.
Chapter 38
255
256 Chapter 38. Date and Time Functionality
Great! You have a variable that gets you the time now.
Amusingly, there’s only one portable way to print out what’s in a time_t, and that’s the rarely-used
ctime() function that prints the value in local time:
now = time(NULL);
printf("%s", ctime(&now));
This returns a string with a very specific form that includes a newline at the end:
Sun Feb 28 18:47:25 2021
So that’s kind of inflexible. If you want more control, you should convert that time_t into a struct tm.
Once you have your time_t in a struct tm, it opens all kinds of doors. You can print out the time in a
variety of ways, figure out which day of the week a date is, and so on. Or convert it back into a time_t.
More on that soon!
time_t some_time_epoch;
some_time_epoch = mktime(&some_time);
printf("%s", ctime(&some_time_epoch));
printf("Is DST: %d\n", some_time.tm_isdst);
Output:
Mon Apr 12 12:00:04 1982
Is DST: 0
When you manually load a struct tm like that, it should be in local time. mktime() will convert that
local time into a time_t calendar time.
Weirdly, however, the standard doesn’t give us a way to load up a struct tm with a UTC time and convert
that to a time_t. If you want to do that with Unix-likes, try the non-standard timegm(). On Windows,
_mkgmtime().
But what if I told you, dear reader, that there’s a way to have much more control over how the date was
printed?
Sure, we could fish individual fields out of the struct tm, but there’s a great function called strftime()
that will do a lot of the hard work for you. It’s like printf(), except for dates!
Let’s see some examples. In each of these, we pass in a destination buffer, a maximum number of char-
acters to write, and then a format string (in the style of—but not the same as—printf()) which tells
strftime() which components of a struct tm to print and how.
You can add other constant characters to include in the output in the format string, as well, just like with
printf().
We get a struct tm in this case from localtime(), but any source works fine.
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 char s[128];
7 time_t now = time(NULL);
8
There are a ton of date printing format specifiers for strftime(), so be sure to check them out in the
strftime() reference page.
38.5. More Resolution with timespec_get() 259
Here’s an example where we get the time and print it out both as integer values and also a floating value:
struct timespec ts;
timespec_get(&ts, TIME_UTC);
Example output:
1614581530 s, 806325800 ns
1614581530.806326 seconds since epoch
struct timespec also makes an appearance in a number of the threading functions that need to be able
to specify time with that resolution.
4 int main(void)
5 {
6 struct tm time_a = {
7 .tm_year=82, // years since 1900
8 .tm_mon=3, // months since January -- [0, 11]
9 .tm_mday=12, // day of the month -- [1, 31]
10 .tm_hour=4, // hours since midnight -- [0, 23]
11 .tm_min=00, // minutes after the hour -- [0, 59]
12 .tm_sec=04, // seconds after the minute -- [0, 60]
13 .tm_isdst=-1, // Daylight Saving Time flag
5
You will on POSIX, where time_t is definitely an integer. Unfortunately the entire world isn’t POSIX, so there we are.
260 Chapter 38. Date and Time Functionality
14 };
15
16 struct tm time_b = {
17 .tm_year=120, // years since 1900
18 .tm_mon=10, // months since January -- [0, 11]
19 .tm_mday=15, // day of the month -- [1, 31]
20 .tm_hour=16, // hours since midnight -- [0, 23]
21 .tm_min=27, // minutes after the hour -- [0, 59]
22 .tm_sec=00, // seconds after the minute -- [0, 60]
23 .tm_isdst=-1, // Daylight Saving Time flag
24 };
25
Output:
1217996816.000000 seconds (38.596783 years) between events
And there you have it! Remember to use difftime() to take the time difference. Even though you can
just subtract on a POSIX system, might as well stay portable.
Chapter 39
Multithreading
C11 introduced, formally, multithreading to the C language. It’s very eerily similar to POSIX threads1 , if
you’ve ever used those.
And if you’ve not, no worries. We’ll talk it through.
Do note, however, that I’m not intending this to be a full-blown classic multithreading how-to2 ; you’ll
have to pick up a different very thick book for that, specifically. Sorry!
Threading is an optional feature. If a C11+ compiler defines __STDC_NO_THREADS__, threads will not
be present in the library. Why they decided to go with a negative sense in that macro is beyond me, but
there we are.
You can test for it like this:
#ifdef __STDC_NO_THREADS__
#error I need threads to build this program!
#endif
Also, you might need to specify certain linker options when building. In the case of Unix-likes, try ap-
pending a -lpthreads to the end of the command line to link the pthreads library3 :
gcc -std=c11 -o foo foo.c -lpthreads
If you’re getting linker errors on your system, it could be because the appropriate library wasn’t included.
39.1 Background
Threads are a way to have all those shiny CPU cores you paid for do work for you in the same program.
Normally, a C program just runs on a single CPU core. But if you know how to split up the work, you can
give pieces of it to a number of threads and have them do the work simultaneously.
Though the spec doesn’t say it, on your system it’s very likely that C (or the OS at its behest) will attempt
to balance the threads over all your CPU cores.
And if you have more threads than cores, that’s OK. You just won’t realize all those gains if they’re all
trying to compete for CPU time.
261
262 Chapter 39. Multithreading
And you can wait for the thread to complete. This is called joining.
Or if you don’t care when the thread completes and don’t want to wait, you can detach it.
A thread can explicitly exit, or it can implicitly call it quits by returning from its main function.
A thread can also sleep for a period of time, doing nothing while other threads run.
The main() program is a thread, as well.
Additionally, we have thread local storage, mutexes, and conditional variables. But more on those later.
Let’s just look at the basics for now.
4
Per §7.1.4¶5.
5
Unless you thrd_detach(). More on this later.
39.4. Creating and Waiting for Threads 263
1 #include <stdio.h>
2 #include <threads.h>
3
4 // This is the function the thread will run. It can be called anything.
5 //
6 // arg is the argument pointer passed to `thrd_create()`.
7 //
8 // The parent thread will get the return value back from `thrd_join()`'
9 // later.
10
20 int main(void)
21 {
22 thrd_t t; // t will hold the thread ID
23 int arg = 3490;
24
25 printf("Launching a thread\n");
26
38 // Wait here for the thread to complete; store the return value
39 // in res:
40
41 thrd_join(t, &res);
42
See how we did the thrd_create() there to call the run() function? Then we did other things in main()
and then stopped and waited for the thread to complete with thrd_join().
The arg that you pass to the function has to have a lifetime long enough so that the thread can pick it up
before it goes away. Also, it needs to not be overwritten by the main thread before the new thread can use
it.
264 Chapter 39. Multithreading
Let’s look at an example that launches 5 threads. One thing to note here is how we use an array of thrd_ts
to keep track of all the thread IDs.
1 #include <stdio.h>
2 #include <threads.h>
3
10 return i;
11 }
12
13 #define THREAD_COUNT 5
14
15 int main(void)
16 {
17 thrd_t t[THREAD_COUNT];
18
19 int i;
20
21 printf("Launching threads...\n");
22 for (i = 0; i < THREAD_COUNT; i++)
23
When I run the threads, I count i up from 0 to 4. And pass a pointer to it to thrd_create(). This pointer
ends up in the run() routine where we make a copy of it.
Simple enough? Here’s the output:
Launching threads...
THREAD 2: running!
THREAD 3: running!
THREAD 4: running!
THREAD 2: running!
Doing other things while the thread runs...
Waiting for thread to complete...
Thread 2 complete!
Thread 2 complete!
39.4. Creating and Waiting for Threads 265
THREAD 5: running!
Thread 3 complete!
Thread 4 complete!
Thread 5 complete!
All threads complete!
Whaaa—? Where’s THREAD 0? And why do we have a THREAD 5 when clearly i is never more than 4
when we call thrd_create()? And two THREAD 2s? Madness!
This is getting into the fun land of race conditions. The main thread is modifying i before the thread has
a chance to copy it. Indeed, i makes it all the way to 5 and ends the loop before the last thread gets a
chance to copy it.
We’ve got to have a per-thread variable that we can refer to so we can pass it in as the arg.
We could have a big array of them. Or we could malloc() space (and free it somewhere—maybe in the
thread itself.)
Let’s give that a shot:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
13 return i;
14 }
15
16 #define THREAD_COUNT 5
17
18 int main(void)
19 {
20 thrd_t t[THREAD_COUNT];
21
22 int i;
23
24 printf("Launching threads...\n");
25 for (i = 0; i < THREAD_COUNT; i++) {
26
35 // ...
Notice on lines 27-30 we malloc() space for an int and copy the value of i into it. Each new thread
gets its own freshly-malloc()d variable and we pass a pointer to that to the run() function.
Once run() makes its own copy of the arg on line 7, it free()s the malloc()d int. And now that it
has its own copy, it can do with it what it pleases.
266 Chapter 39. Multithreading
where the thrd_detach() call is the parent thread saying, “Hey, I’m not going to wait for this child
thread to complete with thrd_join(). So go ahead and clean it up on your own when it completes.”
1 #include <stdio.h>
2 #include <threads.h>
3
11 return 0;
12 }
13
14 #define THREAD_COUNT 10
15
16 int main(void)
17 {
18 thrd_t t;
19
23 }
24
Note that in this code, we put the main thread to sleep for 1 second with thrd_sleep()—more on that
later.
Also in the run() function, I have a commented-out line in there that prints out the thread ID as an
unsigned long. This is non-portable, because the spec doesn’t say what type a thrd_t is under the
hood—it could be a struct for all we know. But that line works on my system.
Something interesting I saw when I ran the code, above, and printed out the thread IDs was that some
threads had duplicate IDs! This seems like it should be impossible, but C is allowed to reuse thread IDs
after the corresponding thread has exited. So what I was seeing was that some threads completed their
run before other threads were launched.
This can lead to race conditions, where you get Weird Things™ happening.
Check out this example. We have a static variable foo in block scope in run(). This variable will be
visible to all threads that pass through the run() function. And the various threads can effectively step
on each others toes.
Each thread copies foo into a local variable x (which is not shared between threads—all the threads have
their own call stacks). So they should be the same, right?
And the first time we print them, they are6 . But then right after that, we check to make sure they’re still
the same.
And they usually are. But not always!
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
9 free(arg);
10
6
Though I don’t think they have to be. It’s just that the threads don’t seem to get rescheduled until some system call like might
happen with a printf()… which is why I have the printf() in there.
268 Chapter 39. Multithreading
26 if (x != foo) {
27 printf("Thread %d: Craziness! x != foo! %d != %d\n", n, x, foo);
28 }
29
32 return 0;
33 }
34
35 #define THREAD_COUNT 5
36
37 int main(void)
38 {
39 thrd_t t[THREAD_COUNT];
40
In thread 1, between the two printf()s, the value of foo somehow changed from 10 to 11, even though
clearly there’s no increment between the printf()s!
It was another thread that got in there (probably thread 0, from the look of it) and incremented the value
of foo behind thread 1’s back!
Let’s solve this problem two different ways. (If you want all the threads to share the variable and not step
on each other’s toes, you’ll have to read on to the mutex section.)
Basically we’re just going to slap this on the front of our block scope static variable and things will
work! It tells C that every thread should have its own version of this variable, so none of them step on
each other’s toes.
The <threads.h> header defines thread_local as an alias to _Thread_local so your code doesn’t
have to look so ugly.
Let’s take the previous example and make foo into a thread_local variable so that we don’t share that
data.
39.6. Thread Local Data 269
9 free(arg);
10
The destructor is type tss_dtor_t which is a pointer to a function that returns void and takes a void* as
an argument (the void* points to the data stored in the variable). In other words, it’s a void (*)(void*),
if that clears it up. Which I admit it probably doesn’t. Check out the example, below.
Generally, thread_local is probably your go-to, but if you like the destructor idea, then you can make
use of that.
The usage is a bit weird in that we need a variable of type tss_t to be alive to represent the value on a per
thread basis. Then we initialize it with tss_create(). Eventually we get rid of it with tss_delete().
Note that calling tss_delete() doesn’t run all the destructors—it’s thrd_exit() (or returning from
the run function) that does that. tss_delete() just releases any memory allocated by tss_create().
In the middle, threads can call tss_set() and tss_get() to set and get the value.
In the following code, we set up the TSS variable before creating the threads, then clean up after the
threads.
In the run() function, the threads malloc() some space for a string and store that pointer in the TSS
variable.
When the thread exits, the destructor function (free() in this case) is called for all the threads.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
5 tss_t str;
6
7 void some_function(void)
8 {
9 // Retrieve the per-thread value of this string
10 char *tss_string = tss_get(str);
270 Chapter 39. Multithreading
11
12 // And print it
13 printf("TSS string: %s\n", tss_string);
14 }
15
34 #define THREAD_COUNT 15
35
36 int main(void)
37 {
38 thrd_t t[THREAD_COUNT];
39
Again, this is kind of a painful way of doing things compared to thread_local, so unless you really need
that destructor functionality, I’d use that instead.
39.7 Mutexes
If you want to only allow a single thread into a critical section of code at a time, you can protect that
section with a mutex7 .
For example, if we had a static variable and we wanted to be able to get and set it in two operations
without another thread jumping in the middle and corrupting it, we could use a mutex for that.
7
Short for “mutual exclusion”, AKA a “lock” on a section of code that only one thread is permitted to execute.
39.7. Mutexes 271
You can acquire a mutex or release it. If you attempt to acquire the mutex and succeed, you may continue
execution. If you attempt and fail (because someone else holds it), you will block8 until the mutex is
released.
If multiple threads are blocked waiting for a mutex to be released, one of them will be chosen to run (at
random, from our perspective), and the others will continue to sleep.
The gameplan is that first we’ll initialize a mutex variable to make it ready to use with mtx_init().
Then subsequent threads can call mtx_lock() and mtx_unlock() to get and release the mutex.
When we’re completely done with the mutex, we can destroy it with mtx_destroy(), the logical opposite
of mtx_init().
First, let’s look at some code that does not use a mutex, and endeavors to print out a shared (static)
serial number and then increment it. Because we’re not using a mutex over the getting of the value (to
print it) and the setting (to increment it), threads might get in each other’s way in that critical section.
1 #include <stdio.h>
2 #include <threads.h>
3
12 serial++;
13
14 return 0;
15 }
16
17 #define THREAD_COUNT 10
18
19 int main(void)
20 {
21 thrd_t t[THREAD_COUNT];
22
8
That is, your process will go to sleep.
272 Chapter 39. Multithreading
Thread running! 9
Clearly multiple threads are getting in there and running the printf() before anyone gets a change to
update the serial variable.
What we want to do is wrap the getting of the variable and setting of it into a single mutex-protected
stretch of code.
We’ll add a new variable to represent the mutex of type mtx_t in file scope, initialize it, and then the
threads can lock and unlock it in the run() function.
1 #include <stdio.h>
2 #include <threads.h>
3
19 serial++;
20
21 // Done getting and setting the data, so free the lock. This will
22 // unblock threads on the mtx_lock() call:
23
26 return 0;
27 }
28
29 #define THREAD_COUNT 10
30
31 int main(void)
32 {
33 thrd_t t[THREAD_COUNT];
34
49
See how on lines 38 and 50 of main() we initialize and destroy the mutex.
But each individual thread acquires the mutex on line 15 and releases it on line 24.
In between the mtx_lock() and mtx_unlock() is the critical section, the area of code where we don’t
want multiple threads mucking about at the same time.
And now we get proper output!
Thread running! 0
Thread running! 1
Thread running! 2
Thread running! 3
Thread running! 4
Thread running! 5
Thread running! 6
Thread running! 7
Thread running! 8
Thread running! 9
If you need multiple mutexes, no problem: just have multiple mutex variables.
And always remember the Number One Rule of Multiple Mutexes: Unlock mutexes in the opposite order
in which you lock them!
Type Description
mtx_plain Regular ol’ mutex
mtx_timed Mutex that supports timeouts
mtx_plain|mtx_recursive Recursive mutex
mtx_timed|mtx_recursive Recursive mutex that supports timeouts
“Recursive” means that the holder of a lock can call mtx_lock() multiple times on the same lock. (They
have to unlock it an equal number of times before anyone else can take the mutex.) This might ease coding
from time to time, especially if you call a function that needs to lock the mutex when you already hold
the mutex.
And the timeout gives a thread a chance to try to get the lock for a while, but then bail out if it can’t get it
in that timeframe.
For a timeout mutex, be sure to create it with mtx_timed:
mtx_init(&serial_mtx, mtx_timed);
And then when you wait for it, you have to specify a time in UTC when it will unlock9 .
The function timespec_get() from <time.h> can be of assistance here. It’ll get you the current time in
UTC in a struct timespec which is just what we need. In fact, it seems to exist merely for this purpose.
It has two fields: tv_sec has the current time in seconds since epoch, and tv_nsec has the nanoseconds
(billionths of a second) as the “fractional” part.
So you can load that up with the current time, and then add to it to get a specific timeout.
9
You might have expected it to be “time from now”, but you’d just like to think that, wouldn’t you!
274 Chapter 39. Multithreading
Then call mtx_timedlock() instead of mtx_lock(). If it returns the value thrd_timedout, it timed
out.
struct timespec timeout;
if (result == thrd_timedout) {
printf("Mutex lock timed out!\n");
}
Other than that, timed locks are the same as regular locks.
But how’s this all work? Let’s look at the outline of what the child thread will do:
1. Lock the mutex with mtx_lock()
2. If we haven’t entered all the numbers, wait on the condition variable with cnd_wait()
3. Do the work that needs doing
4. Unlock the mutex with mtx_unlock()
Meanwhile the main thread will be doing this:
1. Lock the mutex with mtx_lock()
2. Store the recently-read number into the array
3. If the array is full, signal the child to wake up with cnd_signal()
39.8. Condition Variables 275
4 #define VALUE_COUNT_MAX 5
5
10
And that’s why they’re called condition variables!
11
I’m not saying it’s aliens… but it’s aliens. OK, really more likely another thread might have been woken up and gotten to the
work first.
276 Chapter 39. Multithreading
16 for (;;) {
17 mtx_lock(&value_mtx); // <-- GRAB THE MUTEX
18
24 printf("Thread: is awake!\n");
25
26 int t = 0;
27
28 // Add everything up
29 for (int i = 0; i < VALUE_COUNT_MAX; i++)
30 t += value[i];
31
40 return 0;
41 }
42
43 int main(void)
44 {
45 thrd_t t;
46
54 mtx_init(&value_mtx, mtx_plain);
55 cnd_init(&value_cnd);
56
57 for (;;) {
58 int n;
59
60 scanf("%d", &n);
61
64 value[value_count++] = n;
65
66 if (value_count == VALUE_COUNT_MAX) {
67 printf("Main: signaling thread\n");
68 cnd_signal(&value_cnd); // <-- SIGNAL CONDITION
69 }
39.8. Condition Variables 277
70
77 mtx_destroy(&value_mtx);
78 cnd_destroy(&value_cnd);
79 }
And here’s some sample output (individual numbers on lines are my input):
Thread: is waiting
1
1
1
1
1
Main: signaling thread
Thread: is awake!
Thread: total is 5
Thread: is waiting
2
8
5
9
0
Main: signaling thread
Thread: is awake!
Thread: total is 24
Thread: is waiting
It’s a common use of condition variables in producer-consumer situations like this. If we didn’t have a
way to put the child thread to sleep while it waited for some condition to be met, it would be force to poll
which is a big waste of CPU.
The timestamp is an absolute time in UTC, not a time-from-now. Thankfully the timespec_get() func-
tion in <time.h> seems custom-made for exactly this case.
struct timespec timeout;
if (result == thrd_timedout) {
printf("Condition variable timed out!\n");
278 Chapter 39. Multithreading
void run_once_function(void)
{
printf("I'll only run once!\n");
}
call_once(&of, run_once_function);
// ...
In this example, no matter how many threads get to the run() function, the run_once_function() will
only be called a single time.
12
Survival of the fittest! Right? I admit it’s actually nothing like that.
Chapter 40
Atomics
If those tests pass, then you can safely include <stdatomic.h>, the header on which the rest of this
chapter is based. But if there is no atomic support, that header might not even exist.
On some systems, you might need to add -latomic to the end of your compilation command line to use
any functions in the header file.
279
280 Chapter 40. Atomics
It’s almost like there’s a little lock around the getting and setting of that one variable. (And there might
be! See Lock-Free Atomic Variables, below.)
And on that note, you can get away with never using atomics if you use mutexes to lock your critical
sections. It’s just that there are a class of lock-free data structures that always allow other threads to make
progress instead of being blocked by a mutex… but these are tough to create correctly from scratch, and
are one of the things that are beyond the scope of the guide, sadly.
That’s only part of the story. But it’s the part we’ll start with.
Before we go further, how do you declare a variable to be atomic?
First, include <stdatomic.h>.
This gives us types such as atomic_int.
And then we can simply declare variables to be of that type.
But let’s do a demo where we have two threads. The first runs for a while and then sets a variable to a
specific value, then exits. The other runs until it sees that value get set, and then it exits.
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
17 printf("Thread 1: Exiting\n");
18 return 0;
19 }
20
32 int main(void)
33 {
34 x = 0;
35
41 thrd_join(t1, NULL);
40.3. Synchronization 281
42 thrd_join(t2, NULL);
43
The second thread spins in place, looking at the flag and waiting for it to get set to the value 3490. And
the first one does that.
And I get this output:
Thread 1: Sleeping for 1.5 seconds
Thread 2: Waiting for 3490
Thread 1: Setting x to 3490
Thread 1: Exiting
Thread 2: Got 3490--exiting!
Main : Threads are done, so x better be 3490
Main : And indeed, x == 3490
Look, ma! We’re accessing a variable from different threads and not using a mutex! And that’ll work
every time thanks to the atomic nature of atomic variables.
You might be wondering what happens if that’s a regular non-atomic int, instead. Well, on my system it
still works… unless I do an optimized build in which case it hangs on thread 2 waiting to see the 3490 to
get set2 .
But that’s just the beginning of the story. The next part is going to require more brain power and has to
do with something called synchronization.
40.3 Synchronization
The next part of our story is all about when certain memory writes in one thread become visible to those
in another thread.
You might think, it’s right away, right? But it’s not. A number of things can go wrong. Weirdly wrong.
The compiler might have rearranged memory accesses so that when you think you set a value relative to
another might not be true. And even if the compiler didn’t, your CPU might have done it on the fly. Or
maybe there’s something else about this architecture that causes writes on one CPU to be delayed before
they’re visible on another.
The good news is that we can condense all these potential troubles into one: unsynchronized memory
accesses can appear out of order depending on which thread is doing the observing, as if the lines of code
themselves had been rearranged.
By way of example, which happens first in the following code, the write to x or the write to y?
1 int x, y; // global
2
3 // ...
4
5 x = 2;
6 y = 3;
7
Answer: we don’t know. The compiler or CPU could silently reverse lines 5 and 6 and we’d be none-the-
wiser. The code would run single-threaded as-if it were executed in code order.
In a multithreaded scenario, we might have something like this pseudocode:
2
The reason for this is when optimized, my compiler has put the value of x in a register to make the while loop fast. But the
register has no way of knowing that the variable was updated in another thread, so it never sees the 3490. This isn’t really related
to the all-or-nothing part of atomicity, but is more related to the synchronization aspects in the next section.
282 Chapter 40. Atomics
1 int x = 0, y = 0;
2
3 thread1() {
4 x = 2;
5 y = 3;
6 }
7
8 thread2() {
9 while (y != 3) {} // spin
10 printf("x is now %d\n", x); // 2? ...or 0?
11 }
But something sneaky could rearrange lines 4 and 5 causing us to see the value of 0 for x when we print
it.
In other words, all bets are off unless we can somehow say, “As of this point, I expect all previous writes
in another thread to be visible in this thread.”
Two threads synchronize when they agree on the state of shared memory. As we’ve seen, they’re not
always in agreement with the code. So how do they agree?
Using atomic variables can force the agreement3 . If a thread writes to an atomic variable, it’s saying
“anyone who reads this atomic variable in the future will also see all the changes I made to memory
(atomic or not) up to and including the atomic variable”.
Or, in more human terms, let’s sit around the conference table and make sure we’re on the same page as
to which pieces of shared memory hold what values. You agree that the memory changes that you’d made
up-to-and-including the atomic store will be visible to me after I do a load of the same atomic variable.
So we can easily fix our example:
1 int x = 0;
2 atomic int y = 0; // Make y atomic
3
4 thread1() {
5 x = 2;
6 y = 3; // Synchronize on write
7 }
8
9 thread2() {
10 while (y != 3) {} // Synchronize on read
11 printf("x is now %d\n", x); // 2, period.
12 }
Because the threads synchronize across y, all writes in thread 1 that happened before the write to y are
visible in thread 2 after the read from y (in the while loop).
It’s important to note a couple things here:
1. Nothing sleeps. The synchronization is not a blocking operation. Both threads are running full bore
until they exit. Even the one stuck in the spin loop isn’t blocking anyone else from running.
2. The synchronization happens when one thread reads an atomic variable another thread wrote. So
when thread 2 reads y, all previous memory writes in thread 1 (namely setting x) will be visible in
thread 2.
3
Until I say otherwise, I’m speaking generally about sequentially consistent operations. More on what that means soon.
40.4. Acquire and Release 283
3. Notice that x isn’t atomic. That’s OK because we’re not synchronizing over x, and the synchroniza-
tion over y when we write it in thread 1 means that all previous writes—including x—in thread 1
will become visible to other threads… if those other threads read y to synchronize.
Forcing this synchronization is inefficient and can be a lot slower than just using a regular variable. This
is why we don’t use atomics unless we have to for a particular application.
So that’s the basics. Let’s look deeper.
int x, y, z = 0;
atomic_int a = 0;
thread1() {
x = 10;
y = 20;
a = 999; // Release
z = 30;
}
thread2()
{
while (a != 999) { } // Acquire
In the above example, thread2 can be sure of the values in x and y after it acquires a because they were
set before thread1 released the atomic a.
But thread2 can’t be sure of z’s value because it happened after the release. Maybe the assignment to z
got moved before the assignment to a.
An important note: releasing one atomic variable has no effect on acquires of different atomic variables.
Each variable is isolated from the others.
More on that later, but for now, let’s stick to the safe and practical.
thread1() {
x = x + 3; // NOT atomic!
}
Since there’s a read of x on the right hand side of the assignment and a write effectively on the left, these
are two operations. Another thread could sneak in the middle and make you unhappy.
But you can use the shorthand += to get an atomic operation:
atomic_int x = 0;
thread1() {
x += 3; // ATOMIC!
}
In that case, x will be atomically incremented by 3—no other thread can jump in the middle.
In particular, the following operators are atomic read-modify-write operations with sequential consistency,
so use them with gleeful abandon. (In the example, a is atomic.)
a++ a-- --a ++a
a += b a -= b a *= b a /= b a %= b
a &= b a |= b a ^= b a >>= b a <<= b
call_once(): synchronizes with all subsequent calls to call_once() for a particular flag. This way
subsequent calls can rest assured that if another thread sets the flag, they will see it.
thrd_create(): synchronizes with the beginning of the new thread. The new thread can be sure it will
see all shared memory writes from the parent thread from before the thrd_create() call.
thrd_join(): when a thread dies, it synchronizes with this function. The thread that has called
thrd_join() can be assured that it can see all the late thread’s shared writes.
mtx_lock(): earlier calls to mtx_unlock() on the same mutex synchronize on this call. This is the
case that most mirrors the acquire/release process we’ve already talked about. mtx_unlock() performs
a release on the mutex variable, assuring any subsequent thread that makes an acquire with mtx_lock()
can see all the shared memory changes in the critical section.
mtx_timedlock() and mtx_trylock(): similar to the situation with mtx_lock(), if this call succeeds,
earlier calls to mtx_unlock() synchronize with this one.
Dynamic Memory Functions: if you allocate memory, it synchronizes with the previous deallocation
of that same memory. And allocations and deallocations of that particular memory region happen in a
single total order that all threads can agree upon. I think the idea here is that the deallocation can wipe the
286 Chapter 40. Atomics
region if it chooses, and we want to be sure that a subsequent allocation doesn’t see the non-wiped data.
Someone let me know if there’s more to it.
Use those at will! They’re consistent with the atomic aliases found in C++, if that helps.
But what if you want more?
You can do it either with a type qualifier or type specifier.
First, specifier! It’s the keyword _Atomic with a type in parens after5 —suitable for use with typedef:
5
Apparently C++23 is adding this as a macro.
40.9. Lock-Free Atomic Variables 287
atomic_double f;
Restrictions on the specifier: the type you’re making atomic can’t be of type array or function, nor can it
be atomic or otherwise qualified.
Next, qualifier! It’s the keyword _Atomic without a type in parens.
So these do similar things6 :
_Atomic(int) i; // type specifier
_Atomic int j; // type qualifier
The thing is, you can include other type qualifiers with the latter:
_Atomic volatile int k; // qualified atomic variable
Restrictions on the qualifier: the type you’re making atomic can’t be of type array or function.
Value Meaning
0 Never lock-free.
1 Sometimes lock-free.
2 Always lock-free.
6
The spec notes that they might differ in size, representation, and alignment.
288 Chapter 40. Atomics
Wait—how can something be sometimes lock-free? This just means the answer isn’t known at compile-
time, but could later be known at runtime. Maybe the answer varies depending on whether or not you’re
running this code on Genuine Intel or AMD, or something like that7 .
But you can always test at runtime with the atomic_is_lock_free() function. This function returns
true or false if the particular type is atomic right now.
So why do we care?
Lock-free is faster, so maybe there’s a speed concern that you’d code around another way. Or maybe you
need to use an atomic variable in a signal handler.
You can set the flag atomically with atomic_flag_test_and_set(), which will set the flag and return
its previous status as a _Bool (true for set).
You can clear the flag atomically with atomic_flag_clear().
Here’s an example where we init the flag to clear, set it twice, then clear it again.
#include <stdio.h>
#include <stdbool.h>
#include <stdatomic.h>
atomic_flag f = ATOMIC_FLAG_INIT;
int main(void)
{
bool r = atomic_flag_test_and_set(&f);
printf("Value was: %d\n", r); // 0
r = atomic_flag_test_and_set(&f);
printf("Value was: %d\n", r); // 1
atomic_flag_clear(&f);
7
I just pulled that example out of nowhere. Maybe it doesn’t matter on Intel/AMD, but it could matter somewhere, dangit!
8
C++ elaborates that if the signal is the result of a call to raise(), it is sequenced after the raise().
9
https://en.wikipedia.org/wiki/Test-and-set
40.11. Atomic structs and unions 289
r = atomic_flag_test_and_set(&f);
printf("Value was: %d\n", r); // 0
}
4 int main(void)
5 {
6 struct point {
7 float x, y;
8 };
9
10 _Atomic(struct point) p;
11
Here’s the catch: you can’t access fields of an atomic struct or union… so what’s the point? Well, you
can atomically copy the entire struct into a non-atomic variable and then use it. You can atomically
copy the other way, too.
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 struct point {
7 float x, y;
8 };
9
10 _Atomic(struct point) p;
11 struct point t;
12
17 t = p; // Atomic copy
18
You can also declare a struct where individual fields are atomic. It is implementation defined if atomic
types are allowed on bitfields.
_Atomic int x;
_Atomic int *p; // p is a pointer to an atomic int
p = &x; // OK!
Second, atomic pointers to non-atomic values (i.e. the pointer value itself is atomic, but the thing it points
to is not):
int x;
int * _Atomic p; // p is an atomic pointer to an int
p = &x; // OK!
Lastly, atomic pointers to atomic values (i.e. the pointer and the thing it points to are both atomic):
_Atomic int x;
_Atomic int * _Atomic p; // p is an atomic pointer to an atomic int
p = &x; // OK!
memory_order Description
memory_order_seq_cst Sequential Consistency
memory_order_acq_rel Acquire/Release
memory_order_release Release
memory_order_acquire Acquire
memory_order_consume Consume
memory_order_relaxed Relaxed
You can specify other ones with certain library functions. For example, you can add a value to an atomic
variable like this:
atomic_int x = 0;
atomic_fetch_add_explicit(&x, 5, memory_order_seq_cst);
But what if we didn’t want sequential consistency? And you wanted acquire/release instead for whatever
reason? Just name it:
atomic_int x = 0;
atomic_fetch_add_explicit(&x, 5, memory_order_acq_rel);
40.13. Memory Order 291
We’ll do a breakdown of the different memory orders, below. Don’t mess with anything other than se-
quential consistency unless you know what you’re doing. It’s really easy to make mistakes that will cause
rare, hard-to-repro failures.
40.13.2 Acquire
This is what happens on a load/read operation on an atomic variable.
• If another thread released this atomic variable, all the writes that thread did are now visible in this
thread.
• Memory accesses in this thread that happen after this load can’t be reordered before it.
40.13.3 Release
This is what happens on a store/write of an atomic variable.
• If another thread later acquires this atomic variable, all memory writes in this thread before its
atomic write become visible to that other thread.
• Memory accesses in this thread that happen before the release can’t be reordered after it.
40.13.4 Consume
This is an odd one, similar to a less-strict version of acquire. It affects memory accesses that are data
dependent on the atomic variable.
Being “data dependent” vaguely means that the atomic variable is used in a calculation.
That is, if a thread consumes an atomic variable then all the operations in that thread that go on to use that
atomic variable will be able to see the memory writes in the releasing thread.
Compare to acquire where memory writes in the releasing thread will be visible to all operations in the
current thread, not just the data-dependent ones.
Also like acquire, there is a restriction on which operations can be reordered before the consume. With
acquire, you couldn’t reorder anything before it. With consume, you can’t reorder anything that depends
on the loaded atomic value before it.
40.13.5 Acquire/Release
This only applies to read-modify-write operations. It’s an acquire and release bundled into one.
• An acquire happens for the read.
• A release happens for the write.
40.13.6 Relaxed
No rules; it’s anarchy! Everyone can reorder everything everywhere! Dogs and cats living together—mass
hysteria!
Actually, there is a rule. Atomic reads and writes are still all-or-nothing. But the operations can be
reordered whimsically and there is zero synchronization between threads.
292 Chapter 40. Atomics
There are a few use cases for this memory order, which you can find with a tiny bit of searching, e.g. simple
counters.
And you can use a fence to force synchronization after a bunch of relaxed writes.
40.14 Fences
You know how the releases and acquires of atomic variables occur as you read and write them?
Well, it’s possible to do a release or acquire without an atomic variable, as well.
This is called a fence. So if you want all the writes in a thread to be visible elsewhere, you can put up a
release fence in one thread and an acquire fence in another, just like with how atomic variables work.
Since a consume operation doesn’t really make sense on a fence10 , memory_order_consume is treated
as an acquire.
You can put up a fence with any specified order:
atomic_thread_fence(memory_order_release);
There’s also a light version of a fence for use with signal handlers, called atomic_signal_fence().
It works just the same way as atomic_thread_fence(), except:
• It only deals with visibility of values within the same thread; there is no synchronization with other
threads.
• No hardware fence instructions are emitted.
If you want to be sure the side effects of non-atomic operations (and relaxed atomic operations) are visible
in the signal handler, you can use this fence.
The idea is that the signal handler is executing in this thread, not another, so this is a lighter-weight way
of making sure changes outside the signal handler are visible within it (i.e. they haven’t been reordered).
40.15 References
If you want to learn more about this stuff, here are some of the things that helped me plow through it:
• Herb Sutter’s atomic<> Weapons talk:
– Part 111
– part 212
• Jeff Preshing’s materials13 , in particular:
– An Introduction to Lock-Free Programming14
– Acquire and Release Semantics15
– The Happens-Before Relation16
– The Synchronizes-With Relation17
– The Purpose of memory_order_consume in C++1118
– You Can Do Any Kind of Atomic Read-Modify-Write Operation19
• CPPReference:
10
Because consume is all about the operations that are dependent on the value of the acquired atomic variable, and there is no
atomic variable with a fence.
11
https://www.youtube.com/watch?v=A8eCGOqgvH4
12
https://www.youtube.com/watch?v=KeLBd2EJLOU
13
https://preshing.com/archives/
14
https://preshing.com/20120612/an-introduction-to-lock-free-programming/
15
https://preshing.com/20120913/acquire-and-release-semantics/
16
https://preshing.com/20130702/the-happens-before-relation/
17
https://preshing.com/20130823/the-synchronizes-with-relation/
18
https://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/
19
https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/
40.15. References 293
– Memory Order20
– Atomic Types21
• Bruce Dawson’s Lockless Programming Considerations22
• The helpful and knowledgeable folks on r/C_Programming23
20
https://en.cppreference.com/w/c/atomic/memory_order
21
https://en.cppreference.com/w/c/language/atomic
22
https://docs.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
23
https://www.reddit.com/r/C_Programming/
294 Chapter 40. Atomics
Chapter 41
These don’t see a heck of a lot of use in my experience, but we’ll cover them here for the sake of com-
pleteness.
This is meant to encourage the compiler to make this function call as fast as possible. And, historically,
one way to do this was inlining, which means that the body of the function would be embedded in its
entirety where the call was made. This would avoid all the overhead of setting up the function call and
tearing it down at the expense of larger code size as the function was copied all over the place instead of
being reused.
That would seem to be the end of the story, but it’s not. inline comes with a whole pile of rules that make
for interesting times. I’m not sure I even understand them all, and behavior seems to vary from compiler
to compiler.
The short answer is define the inline function as static in the file that you need it. And then use it in
that one file. And you never have to worry about the rest of it.
But if you’re wondering, here are more fun times.
Let’s try leaving the static off.
1 #include <stdio.h>
2
8 int main(void)
9 {
295
296 Chapter 41. Function Specifiers, Alignment Specifiers/Operators
gcc gives a linker error on add()… unless you compile with optimizations on (probably)!
See, a compiler can choose to inline or not, but if it chooses not to, you’re left with no function at all. gcc
doesn’t inline unless you’re doing an optimized build.
One way around this is to define a non-inline external linkage version of the function elsewhere, and that
one will be used when the inline one isn’t. But you as the programmer can’t determine which, portably.
If both are available, it’s unspecified which one the compiler chooses. With gcc the inline function will
be used if you’re compiling with optimizations, and the non-inline one will be used otherwise. Even if
the bodies of these functions are completely different. Zany!
Another way is to declare the function as extern inline. This will attempt to inline in this file, but
will also create a version with external linkage. And so gcc will use one or the other depending on
optimizations, but at least they’re the same function.
Unless, of course, you have another source file with an inline function of the same name; it will use its
inline function or the one with external linkage depending on optimizations.
But let’s say you’re doing a build where the compiler is inlining the function. In that case, you can just
use a plain inline in the definition. However, there are now additional restrictions.
You can’t refer to any static globals:
static int b = 13;
return x + y + b;
}
return x + y + b;
}
Now, you know the functions are extern by default, so we should be able to call add() from another file.
You’d like to think that, wouldn’t you!
But you can’t! If it’s just a plain inline, it’s similar to static: it’s only visible in that file.
Okay, so what if you throw an extern on there? Now we’re coming full circle to when we discussed
having inline mixed with functions with external linkage.
If both are visible, the compiler can choose which to use.
Let’s do a demo of this behavior. We’ll have two files, foo.c and bar.c. They’ll both call func() which
is inline in foo.c and external linkage in bar.c.
Here’s foo.c with the inline.
41.1. Function Specifiers 297
1 // foo.c
2
3 #include <stdio.h>
4
10 int main(void)
11 {
12 printf("foo.c: %s\n", func());
13
14 void bar(void);
15 bar();
16 }
Recall that unless we’re doing an optimized build with gcc. func() will vanish and we’ll get a linker
error. Unless, or course, we have a version with external linkage defined elsewhere.
And we do. In bar.c.
1 // bar.c
2
3 #include <stdio.h>
4
5 char *func(void)
6 {
7 return "bar's function";
8 }
9
10 void bar(void)
11 {
12 printf("bar.c: %s\n", func());
13 }
And if I compile with gcc with optimizations1 it will use inline functions, and we’ll get the expected:
foo.c: foo's function
bar.c: bar's function
Great!
But if we compile in gcc without optimizations, it ignores the inline function and uses the external linkage
func() from bar.c! And we get this:
foo.c: bar's function
bar.c: bar's function
In short, the rules are surprisingly complex. I give myself a good 30% chance of having described them
correctly.
It allows the compiler to perhaps perform some optimizations around the function call.
It also allows you to indicate to other devs that some program logic depends on a function not returning.
You’ll likely never need to use this, but you’ll see it on some library calls like exit() and abort().
The built-in keyword is _Noreturn, but if it doesn’t break your existing code, everyone would recommend
including <stdnoreturn.h> and using the easier-to-read noreturn instead.
It’s undefined behavior if a function specified as noreturn actually does return. It’s computationally
dishonest, see.
Here’s an example of using noreturn correctly:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdnoreturn.h>
4
12 int main(void)
13 {
14 foo();
15 }
If the compiler detects that a noreturn function could return, it might warn you, helpfully.
Replacing the foo() function with this:
noreturn void foo(void)
{
printf("Breakin' the law\n");
}
gets me a warning:
foo.c:7:1: warning: function declared 'noreturn' should not return
2
https://en.wikipedia.org/wiki/Data_structure_alignment
41.2. Alignment Specifiers and Operators 299
You can also pass a constant value or expression in for the alignment. This has to be something supported
by the system, but the spec stops short of dictating what values you can put in there. Small powers of 2
(1, 2, 4, 8, and 16) are generally safe bets.
char alignas(8) c; // align on 8-byte boundaries
If you want to align at the maximum used alignment by your system, include <stddef.h> and use the
type max_align_t, like so:
char alignas(max_align_t) c;
You could potentially over-align by specifying an alignment more than that of max_align_t, but whether
or not such things are allowed is system dependent.
5 struct t {
6 int a;
7 char b;
8 float c;
9 };
10
11 int main(void)
12 {
13 printf("char : %zu\n", alignof(char));
14 printf("short : %zu\n", alignof(short));
15 printf("int : %zu\n", alignof(int));
16 printf("long : %zu\n", alignof(long));
17 printf("long long : %zu\n", alignof(long long));
18 printf("double : %zu\n", alignof(double));
19 printf("long double: %zu\n", alignof(long double));
20 printf("struct t : %zu\n", alignof(struct t));
21 printf("max_align_t: %zu\n", alignof(max_align_t));
22 }
Output on my system:
char : 1
short : 2
int : 4
long : 8
long long : 8
double : 8
long double: 16
struct t : 16
max_align_t: 16
Macro Description
assert() Runtime assertion
static_assert() Compile-time assertion
This functionality has to do with things that Should Never Happen™. If you have something that should
never be true and you want your program to bomb out because it happened, this is the header file for you.
There are two types of assertions: compile-time assertions (called “static assertions”) and runtime asser-
tions. If the assertion fails (i.e. the thing that you need to be true is not true) then the program will bomb
out either at compile-time or runtime.
42.1 Macros
If you define the macro NDEBUG before you include <assert.h>, then the assert() macro will have no
effect. You can define NDEBUG to be anything, but 1 seems like a good value.
Since assert() causes your program to bomb out at runtime, you might not desire this behavior when
you go into production. Defining NDEBUG causes assert() to be ignored.
NDEBUG has no effect on static_assert().
42.2 assert()
Bomb out at runtime if a condition fails
Synopsis
#include <assert.h>
Description
You pass in an expression to this macro. If it evaluates to false, the program will crash with an assertion
failure (by calling the abort() function).
301
302 Chapter 42. <assert.h> Runtime and Compile-time Diagnostics
Basically, you’re saying, “Hey, I’m assuming this condition is true, and if it’s not, I don’t want to continue
running.”
This is used while debugging to make sure no unexpected conditions arise. And if you find during de-
velopment that the condition does arise, maybe you should modify the code to handle it before going to
production.
If you’ve defined the macro NDEBUG to any value before <assert.h> was included, the assert() macro
is ignored. This is a good idea before production.
Unlike static_assert(), this macro doesn’t allow you to print an arbitrary message. If you want to do
this, check out the example in the Preprocessor chapter.
Return Value
This macro doesn’t return (since it calls abort() which never returns).
If NDEBUG is set, the macro evaluates to ((void)0), which does nothing.
Example
Here’s a function that divides the size of our goat herd. But we’re assuming we’ll never get a 0 passed to
us.
So we assert that amount != 0… and if it is, the program aborts/
1 //#define NDEBUG 1 // uncomment this to disable the assert
2
3 #include <stdio.h>
4 #include <assert.h>
5
12 goat_count /= amount;
13 }
14
15 int main(void)
16 {
17 divide_goat_herd_by(2); // OK
18
When I run this and pass 0 to the function, I get the following on my system (the exact output may vary):
assert: assert.c:10: divide_goat_herd_by: Assertion `amount != 0' failed.
See Also
static_assert(), abort()
42.3 static_assert()
Bomb out at compile-time if a condition fails
42.3. static_assert() 303
Synopsis
#include <assert.h>
static_assert(constant-expression, string-literal);
Description
This macro prevents your program from even compiling if a condition isn’t true.
And it prints the string literal you give it.
Basically if constant-expression is false, then compilation will cease and the string-literal will
be printed.
The constant expression must be truly constant–just values, no variables. And the same is true for the
string literal: no variables, just a literal string in double quotes. (It has to be this way since the program’s
not running at this point.)
Return Value
Not applicable, as this is a compile-time feature.
Example
Here’s a partial example with an algorithm that presumably has poor performance or memory issues if
the size of the local array is too large. We prevent that eventuality at compile-time by catching it with the
static_assert().
1 #include <stdio.h>
2 #include <assert.h>
3
4 #define ARRAY_SIZE 16
5
6 int main(void)
7 {
8 static_assert(ARRAY_SIZE > 32, "ARRAY_SIZE too small");
9
10 int a[ARRAY_SIZE];
11
12 a[32] = 10;
13
14 printf("%d\n", a[32]);
15 }
On my system, when I try to compile it, this prints (your output may vary):
In file included from static_assert.c:2:
static_assert.c: In function ‘main’:
static_assert.c:8:5: error: static assertion failed: "ARRAY_SIZE too small"
8 | static_assert(ARRAY_SIZE > 32, "ARRAY_SIZE too small");
| ^~~~~~~~~~~~~
See Also
assert()
304 Chapter 42. <assert.h> Runtime and Compile-time Diagnostics
Chapter 43
The complex functions in this reference section come in three flavors each: double complex, float
complex, and long double complex.
The float variants end with f and the long double variants end with l, e.g. for complex cosine:
ccos() double complex
ccosf() float complex
ccosl() long double complex
The table below only lists the double complex version for brevity.
Function Description
cabs() Compute the complex absolute value
cacos() Compute the complex arc-cosine
cacosh() Compute the complex arc hyperbolic cosine
carg() Compute the complex argument
casin() Compute the complex arc-sine
casinh() Compute the complex arc hyperbolic sine
catan() Compute the complex arc-tangent
catanh() Compute the complex arc hyperbolic tangent
ccos() Compute the complex cosine
ccosh() Compute the complex hyperbolic cosine
cexp() Compute the complex base-𝑒 exponential
cimag() Returns the imaginary part of a complex number
clog() Compute the complex logarithm
CMPLX() Build a complex value from real and imaginary types
conj() Compute the conjugate of a complex number
cproj() Compute the projection of a complex number
creal() Returns the real part of a complex number
csin() Compute the complex sine
csinh() Compute the complex hyperbolic sine
csqrt() Compute the complex square root
ctan() Compute the complex tangent
ctanh() Compute the complex hyperbolic tangent
You can test for complex number support by looking at the __STDC_NO_COMPLEX__ macro. If it’s defined,
complex numbers aren’t available.
There are possibly two types of numbers defined: complex and imaginary. No system I’m currently aware
of implements imaginary types.
305
306 Chapter 43. <complex.h> Complex Number Functionality
The complex types, which are a real value plus a multiple of 𝑖, are:
float complex
double complex
long double complex
The latter has the advantage of handing special cases of complex numbers correctly (like those involving
infinity or signed zeroes) as if _Imaginary_I were present, even if it’s not.
All angular values are in radians.
Some functions have discontinuities called branch cuts. Now, I’m no mathematician so I can’t really talk
sensibly about this, but if you’re here, I like to think you know what you’re doing when it comes to this
side of things.
If you system has signed zeroes, you can tell which side of the cut you’re on by the sign. And you can’t
if you don’t. The spec elaborates:
Implementations that do not support a signed zero […] cannot distinguish the sides of branch
cuts. These implementations shall map a cut so the function is continuous as the cut is
approached coming around the finite endpoint of the cut in a counter clockwise direction.
(Branch cuts for the functions specified here have just one finite endpoint.) For example,
for the square root function, coming counter clockwise around the finite endpoint of the cut
along the negative real axis approaches the cut from above, so the cut maps to the positive
imaginary axis.
Finally, there’s a pragma called CX_LIMITED_RANGE that can be turned on and off (default is off). You
can turn it on with:
#pragma STDC CX_LIMITED_RANGE ON
It allows for certain intermediate operations to underflow, overflow, or deal badly with infinity, presumably
for a tradeoff in speed. If you’re sure these types of errors won’t occur with the numbers you’re using
AND you’re trying to get as much speed out as you can, you could turn this macro on.
The spec also elaborates here:
The purpose of the pragma is to allow the implementation to use the formulas:
(𝑥 + 𝑖𝑦) × (𝑢 + 𝑖𝑣) = (𝑥𝑢 − 𝑦𝑣) + 𝑖(𝑦𝑢 + 𝑥𝑣)
(𝑥 + 𝑖𝑦)/(𝑢 + 𝑖𝑣) = [(𝑥𝑢 + 𝑦𝑣) + 𝑖(𝑦𝑢 − 𝑥𝑣)]/(𝑢2 + 𝑣2 )
|𝑥 + 𝑖𝑦| = √𝑥2 + 𝑦2
where the programmer can determine they are safe.
43.1. cacos(), cacosf(), cacosl() 307
Synopsis
#include <complex.h>
Description
Computes the complex arc-cosine of a complex number.
The complex number z will have an imaginary component in the range [0, 𝜋], and the real component is
unbounded.
There are branch cuts outside the interval [−1, +1] on the real axis.
Return Value
Returns the complex arc-cosine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 0.195321 + -2.788006i
See Also
ccos(), casin(), catan()
Synopsis
#include <complex.h>
Description
Computes the complex arc-sine of a complex number.
The complex number z will have an imaginary component in the range [−𝜋/2, +𝜋/2], and the real
component is unbounded.
There are branch cuts outside the interval [−1, +1] on the real axis.
Return Value
Returns the complex arc-sine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 1.375476 + 2.788006i
See Also
csin(), cacos(), catan()
Synopsis
#include <complex.h>
Description
Computes the complex arc-tangent of a complex number.
The complex number z will have an real component in the range [−𝜋/2, +𝜋/2], and the imaginary
component is unbounded.
There are branch cuts outside the interval [−𝑖, +𝑖] on the imaginary axis.
Return Value
Returns the complex arc-tangent of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double wheat = 8;
7 double sheep = 1.5708;
8
Output:
Result: 1.450947 + 0.023299i
See Also
ctan(), cacos(), casin()
Synopsis
#include <complex.h>
Description
Computes the complex cosine of a complex number.
Return Value
Returns the complex cosine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: -0.365087 + -2.276818i
See Also
csin(), ctan(), cacos()
Synopsis
#include <complex.h>
Description
Computes the complex sine of a complex number.
Return Value
Returns the complex sine of z.
Example
43.6. ctan(), ctanf(), ctanl() 311
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 2.482485 + -0.334840i
See Also
ccos(), ctan(), casin()
Synopsis
#include <complex.h>
Description
Computes the complex tangent of a complex number.
Return Value
Returns the complex tangent of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: -0.027073 + 1.085990i
See Also
ccos(), csin(), catan()
Synopsis
#include <complex.h>
Description
Computes the complex arc hyperbolic cosine of a complex number.
There is a branch cut at values less than 1 on the real axis.
The return value will be non-negative on the real number axis, and in the range [−𝑖𝜋, +𝑖𝜋] on the imagi-
nary axis.
Return Value
Returns the complex arc hyperbolic cosine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 2.788006 + 0.195321i
See Also
casinh(), catanh(), acosh()
43.8. casinh(), casinhf(), casinhl() 313
Synopsis
#include <complex.h>
Description
Computes the complex arc hyperbolic sine of a complex number.
There are branch cuts outside [−𝑖, +𝑖] on the imaginary axis.
The return value will be unbounded on the real number axis, and in the range [−𝑖𝜋/2, +𝑖𝜋/2] on the
imaginary axis.
Return Value
Returns the complex arc hyperbolic sine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 2.794970 + 0.192476i
See Also
cacosh(), catanh(), asinh()
Synopsis
314 Chapter 43. <complex.h> Complex Number Functionality
#include <complex.h>
Description
Computes the complex arc hyperbolic tangent of a complex number.
There are branch cuts outside [−1, +1] on the real axis.
The return value will be unbounded on the real number axis, and in the range [−𝑖𝜋/2, +𝑖𝜋/2] on the
imaginary axis.
Return Value
Returns the complex arc hyperbolic tangent of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 0.120877 + 1.546821i
See Also
cacosh(), casinh(), atanh()
Synopsis
#include <complex.h>
Description
Computes the complex hyperbolic cosine of a complex number.
Return Value
Returns the complex hyperbolic cosine of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: -0.005475 + 1490.478826i
See Also
csinh(), ctanh(), ccos()
Synopsis
#include <complex.h>
Description
Computes the complex hyperbolic sine of a complex number.
Return Value
Returns the complex hyperbolic sine of z.
Example
316 Chapter 43. <complex.h> Complex Number Functionality
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: -0.005475 + 1490.479161i
See Also
ccosh(), ctanh(), csin()
Synopsis
#include <complex.h>
Description
Computes the complex hyperbolic tangent of a complex number.
Return Value
Returns the complex hyperbolic tangent of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 8 + 1.5708 * I;
7
Output:
Result: 1.000000 + -0.000000i
See Also
ccosh(), csinh(), ctan()
Synopsis
#include <complex.h>
Description
Computes the complex base-𝑒 exponential of z.
Return Value
Returns the complex base-𝑒 exponential of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
Output:
Result: -1.131204 + 2.471727i
See Also
cpow(), clog(), exp()
318 Chapter 43. <complex.h> Complex Number Functionality
Synopsis
#include <complex.h>
Description
Compute the base-𝑒 complex logarithm of z. There is a branch cut on the negative real axis.
The returns value is unbounded on the real axis and in the range [−𝑖𝜋, +𝑖𝜋] on the imaginary axis.
Return Value
Returns the base-𝑒 complex logarithm of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
Output:
Result: 0.804719 + 1.107149i
See Also
cexp(), log()
Synopsis
#include <complex.h>
Description
Computes the complex absolute value of z.
Return Value
Returns the complex absolute value of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
Output:
Result: 2.236068 + 0.000000i
See Also
fabs(), abs()
Synopsis
#include <complex.h>
Description
Computes the complex 𝑥𝑦 .
There is a branch cut for x along the negative real axis.
320 Chapter 43. <complex.h> Complex Number Functionality
Return Value
Returns the complex 𝑥𝑦 .
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7 double complex y = 3 + 4 * I;
8
Result:
Result: 0.129010 + 0.000000i
See Also
csqrt(), cexp()
Synopsis
#include <complex.h>
Description
Computes the complex square root of z.
There is a branch cut along the negative real axis.
The return value is in the right half of the complex plane and includes the imaginary axis.
Return Value
Returns the complex square root of z.
Example
43.18. carg(), cargf(), cargl() 321
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
Output:
Result: 1.272020 + 0.786151i
See Also
cpow(), sqrt()
Synopsis
#include <complex.h>
Description
Computes the complex argument (AKA phase angle) of z.
There is a branch cut along the negative real axis.
Returns a value in the range [−𝜋, +𝜋].
Return Value
Returns the complex argument of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
8 double y = carg(x);
322 Chapter 43. <complex.h> Complex Number Functionality
Output:
Result: 1.107149
Synopsis
#include <complex.h>
Description
Returns the imaginary part of z.
As a footnote, the spec points out that any complex number x is part of the following equivalency:
x == creal(x) + cimag(x) * I;
Return Value
Returns the imaginary part of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
8 double y = cimag(x);
9
See Also
creal()
43.20. CMPLX(), CMPLXF(), CMPLXL() 323
Synopsis
#include <complex.h>
Description
These macros build a complex value from real and imaginary types.
Now I know what you’re thinking. “But I can already build a complex value from real and imaginary
types using the I macro, like in the example you’re about to give us.”
double complex x = 1 + 2 * I;
Return Value
Returns the complex number for the given real x and imaginary y components.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = CMPLX(1, 2); // Like 1 + 2 * I
7
Output:
324 Chapter 43. <complex.h> Complex Number Functionality
See Also
creal(), cimag()
Synopsis
#include <complex.h>
Description
This function computes the complex conjugate1 of z. Apparently it does this by reversing the sign of the
imaginary part, but dammit, I’m a programmer not a mathematician, Jim!
Return Value
Returns the complex conjugate of z
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
Output:
Result: 1.000000 + -2.000000i
Synopsis
#include <complex.h>
Description
Computes the projection of z onto a Riemann sphere2 .
Now we’re really outside my expertise. The spec has this to say, which I’m quoting verbatim because I’m
not knowledgable enough to rewrite it sensibly. Hopefully it makes sense to anyone who would need to
use this function.
z projects to z except that all complex infinities (even those with one infinite part and one
NaN part) project to positive infinity on the real axis. If z has an infinite part, then cproj(z)
is equivalent to
Return Value
Returns the projection of z onto a Riemann sphere.
Example
Fingers crossed this is a remotely sane example…
1 #include <stdio.h>
2 #include <complex.h>
3 #include <math.h>
4
5 int main(void)
6 {
7 double complex x = 1 + 2 * I;
8
13 x = INFINITY + 2 * I;
14 y = cproj(x);
15
Output:
Result: 1.000000 + 2.000000i
Result: inf + 0.000000i
2
https://en.wikipedia.org/wiki/Riemann_sphere
326 Chapter 43. <complex.h> Complex Number Functionality
Synopsis
#include <complex.h>
Description
Returns the real part of z.
As a footnote, the spec points out that any complex number x is part of the following equivalency:
x == creal(x) + cimag(x) * I;
Return Value
Returns the real part of z.
Example
1 #include <stdio.h>
2 #include <complex.h>
3
4 int main(void)
5 {
6 double complex x = 1 + 2 * I;
7
8 double y = creal(x);
9
See Also
cimag()
Chapter 44
Function Description
isalnum() Tests if a character is alphabetic or is a digit
isalpha() Returns true if a character is alphabetic
isblank() Tests if a character is word-separating whitespace
iscntrl() Test if a character is a control character
isdigit() Tests if a character is a digit
isgraph() Tests if the character is printable and not a space
islower() Tests if a character is lowercase
isprint() Tests if a character is printable
ispunct() Test if a character is punctuation
isspace() Test if a character is whitespace
isupper() Tests if a character is uppercase
isxdigit() Tests if a character is a hexadecimal digit
tolower() Convert a letter to lowercase
toupper() Convert a letter to uppercase
This collection of macros is good for testing characters to see if they’re of a certain class, such as alphabetic,
numeric, control characters, etc.
Surprisingly, they take int arguments instead of some kind of char. This is so you can feed EOF in
for convenience if you have an integer representation of that. If not EOF, the value passed in has to be
representable in an unsigned char. Otherwise it’s (dun dun DUUNNNN) undefined behavior. So you
can forget about passing in your UTF-8 multibyte characters.
You can portably avoid this undefined behavior by casting the arguments to these functions to (unsigned
char). This is irksome and ugly, admittedly. The values in the basic character set are all safe to use since
they’re positive values that fit into an unsigned char.
In many of the pages in this section, I give some examples. These are from the “C” locale, and might vary
if you’ve set a different locale.
Note that wide characters have their own set of classification functions, so don’t try to use these on
wchar_ts. Or else!
327
328 Chapter 44. <ctype.h> Character Classification and Conversion
44.1 isalnum()
Tests if a character is alphabetic or is a digit
Synopsis
#include <ctype.h>
Description
Tests if a character is alphabetic (A-Z or a-z) or a digit (0-9).
Is equivalent to:
isalpha(c) || isdigit(c)
Return Value
Returns true if a character is alphabetic (A-Z or a-z) or a digit (0-9).
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isalnum('a')? "yes": "no"); // yes
9 printf("%s\n", isalnum('B')? "yes": "no"); // yes
10 printf("%s\n", isalnum('5')? "yes": "no"); // yes
11 printf("%s\n", isalnum('?')? "yes": "no"); // no
12 }
See Also
isalpha(), isdigit()
44.2 isalpha()
Returns true if a character is alphabetic
Synopsis
#include <ctype.h>
Description
Returns true for alphabetic characters (A-Z or a-z).
Technically (and in the “C” locale) equivalent to:
44.3. isblank() 329
isupper(c) || islower(c)
Extra super technically, because I know you’re dying for this to be extra unnecessarily complex, it can
also include some locale-specific characters for which this is true:
!iscntrl(c) && !isdigit(c) && !ispunct(c) && !isspace(c)
Return Value
Returns true for alphabetic characters (A-Z or a-z).
Or for any of the other crazy stuff in the description, above.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isalpha('a')? "yes": "no"); // yes
9 printf("%s\n", isalpha('B')? "yes": "no"); // yes
10 printf("%s\n", isalpha('5')? "yes": "no"); // no
11 printf("%s\n", isalpha('?')? "yes": "no"); // no
12 }
See Also
isalnum()
44.3 isblank()
Tests if a character is word-separating whitespace
Synopsis
#include <ctype.h>
Description
True if the character is a whitespace character used to separate words in a single line.
For example, space (' ') or horizontal tab ('\t'). Other locales might define other blank characters.
Return Value
Returns true if the character is a whitespace character used to separate words in a single line.
330 Chapter 44. <ctype.h> Character Classification and Conversion
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isblank(' ')? "yes": "no"); // yes
9 printf("%s\n", isblank('\t')? "yes": "no"); // yes
10 printf("%s\n", isblank('\n')? "yes": "no"); // no
11 printf("%s\n", isblank('a')? "yes": "no"); // no
12 printf("%s\n", isblank('?')? "yes": "no"); // no
13 }
See Also
isspace()
44.4 iscntrl()
Test if a character is a control character
Synopsis
#include <ctype.h>
Description
A control character is a locale-specific non-printing character.
For the “C” locale, this means control characters are in the range 0x00 to 0x1F (the character right before
SPACE) and 0x7F (the DEL character).
Basically if it’s not an ASCII (or Unicode less than 128) printable character, it’s a control character in the
“C” locale.
Return Value
Returns true if c is a control character.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", iscntrl('\t')? "yes": "no"); // yes (tab)
9 printf("%s\n", iscntrl('\n')? "yes": "no"); // yes (newline)
10 printf("%s\n", iscntrl('\r')? "yes": "no"); // yes (return)
44.5. isdigit() 331
See Also
isgraph(), isprint()
44.5 isdigit()
Tests if a character is a digit
Synopsis
#include <ctype.h>
Description
Tests if c is a digit in the range 0-9.
Return Value
Returns true if the character is a digit, unsurprisingly.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isdigit('0')? "yes": "no"); // yes
9 printf("%s\n", isdigit('5')? "yes": "no"); // yes
10 printf("%s\n", isdigit('a')? "yes": "no"); // no
11 printf("%s\n", isdigit('B')? "yes": "no"); // no
12 printf("%s\n", isdigit('?')? "yes": "no"); // no
13 }
See Also
isalnum(), isxdigit()
44.6 isgraph()
Tests if the character is printable and not a space
332 Chapter 44. <ctype.h> Character Classification and Conversion
Synopsis
#include <ctype.h>
Description
Tests if c is any printable character that isn’t a space (' ').
Return Value
Returns true if c is any printable character that isn’t a space (' ').
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isgraph('0')? "yes": "no"); // yes
9 printf("%s\n", isgraph('a')? "yes": "no"); // yes
10 printf("%s\n", isgraph('B')? "yes": "no"); // yes
11 printf("%s\n", isgraph('?')? "yes": "no"); // yes
12 printf("%s\n", isgraph(' ')? "yes": "no"); // no
13 printf("%s\n", isgraph('\n')? "yes": "no"); // no
14 }
See Also
iscntrl(), isprint()
44.7 islower()
Tests if a character is lowercase
Synopsis
#include <ctype.h>
Description
Tests if a character is lowercase, in the range a-z.
In other locales, there could be other lowercase characters. In all cases, to be lowercase, the following
must be true:
!iscntrl(c) && !isdigit(c) && !ispunct(c) && !isspace(c)
44.8. isprint() 333
Return Value
Returns true if the character is lowercase.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", islower('c')? "yes": "no"); // yes
9 printf("%s\n", islower('0')? "yes": "no"); // no
10 printf("%s\n", islower('B')? "yes": "no"); // no
11 printf("%s\n", islower('?')? "yes": "no"); // no
12 printf("%s\n", islower(' ')? "yes": "no"); // no
13 }
See Also
isupper(), isalpha(), toupper(), tolower()
44.8 isprint()
Tests if a character is printable
Synopsis
#include <ctype.h>
Description
Tests if a character is printable, including space (' '). So like isgraph(), except space isn’t left out in
the cold.
Return Value
Returns true if the character is printable, including space (' ').
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isprint('c')? "yes": "no"); // yes
9 printf("%s\n", isprint('0')? "yes": "no"); // yes
10 printf("%s\n", isprint(' ')? "yes": "no"); // yes
334 Chapter 44. <ctype.h> Character Classification and Conversion
See Also
isgraph(), iscntrl()
44.9 ispunct()
Test if a character is punctuation
Synopsis
#include <ctype.h>
Description
Tests if a character is punctuation.
In the “C” locale, this means:
!isspace(c) && !isalnum(c)
In other locales, there could be other punctuation characters (but they also can’t be space or alphanumeric).
Return Value
True if the character is punctuation.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", ispunct(',')? "yes": "no"); // yes
9 printf("%s\n", ispunct('!')? "yes": "no"); // yes
10 printf("%s\n", ispunct('c')? "yes": "no"); // no
11 printf("%s\n", ispunct('0')? "yes": "no"); // no
12 printf("%s\n", ispunct(' ')? "yes": "no"); // no
13 printf("%s\n", ispunct('\n')? "yes": "no"); // no
14 }
See Also
isspace(), isalnum()
44.10. isspace() 335
44.10 isspace()
Test if a character is whitespace
Synopsis
#include <ctype.h>
Description
Tests if c is a whitespace character. These are:
• Space (' ')
• Formfeed ('\f')
• Newline ('\n')
• Carriage Return ('\r')
• Horizontal Tab ('\t')
• Vertical Tab ('\v')
Other locales might specify other whitespace characters. isalnum() is false for all whitespace characters.
Return Value
True if the character is whitespace.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isspace(' ')? "yes": "no"); // yes
9 printf("%s\n", isspace('\n')? "yes": "no"); // yes
10 printf("%s\n", isspace('\t')? "yes": "no"); // yes
11 printf("%s\n", isspace(',')? "yes": "no"); // no
12 printf("%s\n", isspace('!')? "yes": "no"); // no
13 printf("%s\n", isspace('c')? "yes": "no"); // no
14 }
See Also
isblank()
44.11 isupper()
Tests if a character is uppercase
Synopsis
336 Chapter 44. <ctype.h> Character Classification and Conversion
#include <ctype.h>
Description
Tests if a character is uppercase, in the range A-Z.
In other locales, there could be other uppercase characters. In all cases, to be uppercase, the following
must be true:
!iscntrl(c) && !isdigit(c) && !ispunct(c) && !isspace(c)
Return Value
Returns true if the character is uppercase.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isupper('B')? "yes": "no"); // yes
9 printf("%s\n", isupper('c')? "yes": "no"); // no
10 printf("%s\n", isupper('0')? "yes": "no"); // no
11 printf("%s\n", isupper('?')? "yes": "no"); // no
12 printf("%s\n", isupper(' ')? "yes": "no"); // no
13 }
See Also
islower(), isalpha(), toupper(), tolower()
44.12 isxdigit()
Tests if a character is a hexadecimal digit
Synopsis
#include <ctype.h>
Description
Returns true if the character is a hexadecimal digit. Namely if it’s 0-9, a-f, or A-F.
Return Value
True if the character is a hexadecimal digit.
44.13. tolower() 337
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 printf("%s\n", isxdigit('B')? "yes": "no"); // yes
9 printf("%s\n", isxdigit('c')? "yes": "no"); // yes
10 printf("%s\n", isxdigit('2')? "yes": "no"); // yes
11 printf("%s\n", isxdigit('G')? "yes": "no"); // no
12 printf("%s\n", isxdigit('?')? "yes": "no"); // no
13 }
See Also
isdigit()
44.13 tolower()
Convert a letter to lowercase
Synopsis
#include <ctype.h>
Description
If the character is uppercase (i.e. isupper(c) is true), this function returns the corresponding lowercase
letter.
Different locales might have different upper- and lowercase letters.
Return Value
Returns the lowercase value for an uppercase letter. If the letter isn’t uppercase, returns it unchanged.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // changing this char
7 // v
8 printf("%c\n", tolower('B')); // b (made lowercase!)
9 printf("%c\n", tolower('e')); // e (unchanged)
10 printf("%c\n", tolower('!')); // ! (unchanged)
11 }
338 Chapter 44. <ctype.h> Character Classification and Conversion
See Also
toupper(), islower(), isupper()
44.14 toupper()
Convert a letter to uppercase
Synopsis
#include <ctype.h>
Description
If the character is lower (i.e. islower(c) is true), this function returns the corresponding uppercase letter.
Different locales might have different upper- and lowercase letters.
Return Value
Returns the uppercase value for a lowercase letter. If the letter isn’t lowercase, returns it unchanged.
Example
1 #include <stdio.h>
2 #include <ctype.h>
3
4 int main(void)
5 {
6 // changing this char
7 // v
8 printf("%c\n", toupper('B')); // B (unchanged)
9 printf("%c\n", toupper('e')); // E (made uppercase!)
10 printf("%c\n", toupper('!')); // ! (unchanged)
11 }
See Also
tolower(), islower(), isupper()
Chapter 45
Variable Description
errno Holds the error status of the last call
This header defines a single variable1 , errno, that can be checked to see if an error has occurred.
errno is set to 0 on startup, but no library function sets it to 0. If you’re going to use solely it to check
for errors, set it to 0 before the call and then check it after. Not only that, but if there’s no error, all library
functions will leave the value of errno unchanged.
Often, though, you’ll get some error indication from the function you’re calling then check errno to see
what went wrong.
This is commonly used in conjunction with perror() to get a human-readable error message that corre-
sponds to the specific error.
Important Safety Tip: You should never make your own variable called errno—that’s undefined behavior.
Note that the C Spec defines less than a handful of values errno can take on. Unix defines a bunch more2 ,
as does Windows3 .
45.1 errno
Holds the error status of the last call
Synopsis
errno // Type is undefined, but it's assignable
Description
Indicates the error status of the last call (note that not all calls will set this value).
Value Description
0 No error
EDOM Domain error (from math)
EILSEQ Encoding error (from character conversion)
1
Really it’s just required to be a modifiable lvalue, so not necessarily a variable. But you can treat it as such.
2
https://man.archlinux.org/man/errno.3.en
3
https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants?view=msvc-160
339
340 Chapter 45. <errno.h> Error Information
Value Description
ERANGE Range error (from math)
If you’re doing a number of math functions, you might come across EDOM or ERANGE.
With multibyte/wide character conversion functions, you might see EILSEQ.
And your system might define any other number of values that errno could be set to, all of which will
begin with the letter E.
Fun Fact: you can use EDOM, EILSEQ, and ERANGE with preprocessor directives such as #ifdef. But,
frankly, I’m not sure why you’d do that other than to test their existence.
Example
The following prints an error message, since passing 2.0 to acos() is outside the function’s domain.
1 #include <stdio.h>
2 #include <math.h>
3 #include <errno.h>
4
5 int main(void)
6 {
7 double x;
8
13 if (errno == EDOM)
14 perror("acos");
15 else
16 printf("Answer is %f\n", x);
17
18 return 0;
19 }
Output:
acos: Numerical argument out of domain
The following prints an error message (on my system), since passing 1e+30 to exp() produces a result
that’s outside the range of a double.
1 #include <stdio.h>
2 #include <math.h>
3 #include <errno.h>
4
5 int main(void)
6 {
7 double x;
8
13 if (errno == ERANGE)
14 perror("exp");
15 else
16 printf("Answer is %f\n", x);
45.1. errno 341
17
18 return 0;
19 }
Output:
exp: Numerical result out of range
This example tries to convert an invalid character into a wide character, failing. This sets errno to EILSEQ.
We then use perror() to print an error message.
1 #include <stdio.h>
2 #include <string.h>
3 #include <wchar.h>
4 #include <errno.h>
5 #include <locale.h>
6
7 int main(void)
8 {
9 setlocale(LC_ALL, "");
10
20 if (result == (size_t)(-1))
21 perror("mbrtowc"); // mbrtowc: Illegal byte sequence
22 else
23 printf("Converted to L'%lc'\n", wc);
24
25 return 0;
26 }
Output:
mbrtowc: Invalid or incomplete multibyte or wide character
See Also
perror(), mbrtoc16(), c16rtomb(), mbrtoc32(), c32rtomb(), fgetwc(), fputwc(), mbrtowc(),
wcrtomb(), mbsrtowcs(), wcsrtombs(), <math.h>,
342 Chapter 45. <errno.h> Error Information
Chapter 46
Function Description
feclearexcept() Clear floating point exceptions
fegetexceptflag() Save the floating point exception flags
fesetexceptflag() Restore the floating point exception flags
feraiseexcept() Raise a floating point exception through software
fetestexcept() Test to see if an exception has occurred
fegetround() Get the rounding direction
fesetround() Set the rounding direction
fegetenv() Save the entire floating point environment
fesetenv() Restore the entire floating point environment
feholdexcept() Save floating point state and install non-stop mode
feupdateenv() Restore floating point environment and apply recent exceptions
Type Description
fenv_t The entire floating point environment
fexcept_t A set of floating point exceptions
The “environment” can be thought of as the status at this moment of the floating point processing system:
this includes the exceptions, rounding, etc. It’s an opaque type, so you won’t be able to access it directly,
and it must be done through the proper functions.
If the functions in question exist on your system (they might not be!), then you’ll also have these macros
defined to represent different exceptions:
Macro Description
FE_DIVBYZERO Division by zero
FE_INEXACT Result was not exact, was rounded
FE_INVALID Domain error
FE_OVERFLOW Numeric overflow
FE_UNDERFLOW Numeric underflow
FE_ALL_EXCEPT All of the above combined
343
344 Chapter 46. <fenv.h> Floating Point Exceptions and Environment
The idea is that you can bitwise-OR these together to represent multiple exceptions, e.g. FE_INVALID|FE_OVERFLOW.
The functions, below, that have an excepts parameter will take these values.
See <math.h> for which functions raise which exceptions and when.
46.2 Pragmas
Normally C is free to optimize all kinds of stuff that might cause the flags to not look like you might
expect. So if you’re going to use this stuff, be sure to set this pragma:
#pragma STDC FENV_ACCESS ON
If you do this at global scope, it remains in effect until you turn it off:
#pragma STDC FENV_ACCESS OFF
If you do it in block scope, it has to come before any statements or declarations. In this case, it has effect
until the block ends (or until it is explicitly turned off.)
A caveat: this program isn’t supported on either of the compilers I have (gcc and clang) as of this writing,
so though I have built the code, below, it’s not particularly well-tested.
46.3 feclearexcept()
Clear floating point exceptions
Synopsis
#include <fenv.h>
Description
If a floating point exception has occurred, this function can clear it.
Set excepts to a bitwise-OR list of exceptions to clear.
Passing 0 has no effect.
Return Value
Returns 0 on success and non-zero on failure.
Example
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 double f = sqrt(-1);
10
11 int r = feclearexcept(FE_INVALID);
46.4. fegetexceptflag() fesetexceptflag() 345
12
See Also
feraiseexcept(), fetestexcept()
Synopsis
#include <fenv.h>
Description
Use these functions to save or restore the current floating point environment in a variable.
Set excepts to the set of exceptions you want to save or restore the state of. Setting it to FE_ALL_EXCEPT
will save or restore the entire state.
Note that fexcept_t is an opaque type—you don’t know what’s in it.
excepts can be set to zero for no effect.
Return Value
Returns 0 on success or if excepts is zero.
Returns non-zero on failure.
Example
This program √saves the state (before any error has happened), then deliberately causes a domain error by
trying to take −1.
After that, it restores the floating point state to before the error had occurred, thereby clearing it.
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 fexcept_t flag;
10
15
16 if (fetestexcept(FE_INVALID))
17 printf("1: Domain error\n"); // This prints!
18 else
19 printf("1: No domain error\n");
20
23 if (fetestexcept(FE_INVALID))
24 printf("2: Domain error\n");
25 else
26 printf("2: No domain error\n"); // This prints!
27 }
46.5 feraiseexcept()
Raise a floating point exception through software
Synopsis
#include <fenv.h>
Description
This attempts to raise a floating point exception as if it had happened.
You can specify multiple exceptions to raise.
If either FE_UNDERFLOW or FE_OVERFLOW is raised, C might also raise FE_INEXACT.
If either FE_UNDERFLOW or FE_OVERFLOW is raised at the same time as FE_INEXACT, then FE_UNDERFLOW
or FE_OVERFLOW will be raised before FE_INEXACT behind the scenes.
The order the other exceptions are raised is undefined.
Return Value
Returns 0 if all the exceptions were raised or if excepts is 0.
Returns non-zero otherwise.
Example
This code deliberately raises a division-by-zero exception and then detects it.
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 feraiseexcept(FE_DIVBYZERO);
10
11 if (fetestexcept(FE_DIVBYZERO) == FE_DIVBYZERO)
46.6. fetestexcept() 347
See Also
feclearexcept(), fetestexcept()
46.6 fetestexcept()
Test to see if an exception has occurred
Synopsis
#include <fenv.h>
Description
Put the exceptions you want to test in excepts, bitwise-ORing them together.
Return Value
Returns the bitwise-OR of the exceptions that have been raised.
Example
This code deliberately raises a division-by-zero exception and then detects it.
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 feraiseexcept(FE_DIVBYZERO);
10
11 if (fetestexcept(FE_DIVBYZERO) == FE_DIVBYZERO)
12 printf("Detected division by zero\n"); // This prints!!
13 else
14 printf("This is fine.\n");
15 }
See Also
feclearexcept(), feraiseexcept()
348 Chapter 46. <fenv.h> Floating Point Exceptions and Environment
Synopsis
#include <fenv.h>
int fegetround(void);
Description
Use these to get or set the rounding direction used by a variety of math functions.
Basically when a function “rounds” a number, it wants to know how to do it. By default, it does it how
we tend to expect: if the fractional part is less than 0.5, it rounds down closer to zero, otherwise up farther
from zero.
Macro Description
FE_TONEAREST Round to the nearest whole number, the default
FE_TOWARDZERO Round toward zero always
FE_DOWNWARD Round toward the next lesser whole number
FE_UPWARD Round toward the next greater whole number
Some implementations don’t support rounding. If it does, the above macros will be defined.
Note that the round() function is always “to-nearest” and doesn’t pay attention to the rounding mode.
Return Value
fegetround() returns the current rounding direction, or a negative value on error.
Example
This rounds some numbers
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
15 return "Unknown";
16 }
17
18 int main(void)
46.8. fegetenv() fesetenv() 349
19 {
20 #pragma STDC FENV_ACCESS ON
21
22 int rm;
23
24 rm = fegetround();
25
31 rm = fegetround();
32
Output:
FE_TONEAREST
2.000000 3.000000
FE_TOWARDZERO
2.000000 2.000000
See Also
nearbyint(), nearbyintf(), nearbyintl(), rint(), rintf(), rintl(), lrint(), lrintf(),
lrintl(), llrint(), llrintf(), llrintl()
Synopsis
#include <fenv.h>
Description
You can save the environment (exceptions, rounding direction, etc.) by calling fegetenv() and restore
it with fesetenv().
Use this if you want to restore the state after a function call, i.e. hide from the caller that some floating
point exceptions or changes occurred.
Return Value
fegetenv() and fesetenv() return 0 on success, and non-zero otherwise.
Example
This example saves the environment, messes with the rounding and exceptions, then restores it. After the
environment is restored, we see that the rounding is back to default and the exception is cleared.
350 Chapter 46. <fenv.h> Floating Point Exceptions and Environment
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 void show_status(void)
6 {
7 printf("Rounding is FE_TOWARDZERO: %d\n",
8 fegetround() == FE_TOWARDZERO);
9
14 int main(void)
15 {
16 #pragma STDC FENV_ACCESS ON
17
18 fenv_t env;
19
25 show_status();
26
29 show_status();
30 }
Output:
Rounding is FE_TOWARDZERO: 1
FE_DIVBYZERO is set: 1
Rounding is FE_TOWARDZERO: 0
FE_DIVBYZERO is set: 0
See Also
feholdexcept(), feupdateenv()
46.9 feholdexcept()
Save floating point state and install non-stop mode
Synopsis
#include <fenv.h>
Description
This is just like fegetenv() except that it updates the current environment to be in non-stop mode, namely
it won’t halt on any exceptions.
46.10. feupdateenv() 351
It remains in this state until you restore the state with fesetenv() or feupdateenv().
Return Value
Example
This example saves the environment and goes into non-stop mode, messes with the rounding and excep-
tions, then restores it. After the environment is restored, we see that the rounding is back to default and
the exception is cleared. We’ll also be out of non-stop mode.
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 void show_status(void)
6 {
7 printf("Rounding is FE_TOWARDZERO: %d\n",
8 fegetround() == FE_TOWARDZERO);
9
14 int main(void)
15 {
16 #pragma STDC FENV_ACCESS ON
17
18 fenv_t env;
19
26 show_status();
27
30 show_status();
31 }
See Also
fegetenv(), fesetenv(), feupdateenv()
46.10 feupdateenv()
Restore floating point environment and apply recent exceptions
Synopsis
#include <fenv.h>
Description
This is like fesetenv() except that it modifies the passed-in environment so that it is updated with
exceptions that have happened in the meantime.
So let’s say you had a function that might raise exceptions, but you wanted to hide those in the caller. One
option might be to:
1. Save the environment with fegetenv() or feholdexcept().
2. Do whatever you do that might raise exceptions.
3. Restore the environment with fesetenv(), thereby hiding the exceptions that happened in step 2.
But that hides all exceptions. What if you just wanted to hide some of them? You could use feupda-
teenv() like this:
Return Value
Returns 0 on success, non-zero otherwise.
Example
This program saves state, raises some exceptions, then clears one of the exceptions, then restores and
updates the state.
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 void show_status(void)
6 {
7 printf("FE_DIVBYZERO: %d\n", fetestexcept(FE_DIVBYZERO) != 0);
8 printf("FE_INVALID : %d\n", fetestexcept(FE_INVALID) != 0);
9 printf("FE_OVERFLOW : %d\n\n", fetestexcept(FE_OVERFLOW) != 0);
10 }
11
12 int main(void)
13 {
14 #pragma STDC FENV_ACCESS ON
15
16 fenv_t env;
17
25 show_status();
26
27 feclearexcept(FE_INVALID);
28
31 show_status();
32 }
In the output, at first we have no exceptions. Then we have the three we raised. Then after we re-
store/update the environment, we see the one we cleared (FE_INVALID) hasn’t been applied:
FE_DIVBYZERO: 0
FE_INVALID : 0
FE_OVERFLOW : 0
FE_DIVBYZERO: 1
FE_INVALID : 1
FE_OVERFLOW : 1
FE_DIVBYZERO: 1
FE_INVALID : 0
FE_OVERFLOW : 1
See Also
fegetenv(), fesetenv(), feholdexcept(), feclearexcept()
354 Chapter 46. <fenv.h> Floating Point Exceptions and Environment
Chapter 47
355
356 Chapter 47. <float.h> Floating Point Limits
The minimum and maximum values here are from the spec—they should what you can at least expect
across all platforms. Your super dooper machine might do better, still!
47.1 Background
The spec allows a lot of leeway when it comes to how C represents floating point numbers. This header
file spells out the limits on those numbers.
It gives a model that can describe any floating point number that I know you’re going to absolutely love.
It looks like this:
𝑝
𝑥 = 𝑠𝑏𝑒 ∑ 𝑓𝑘 𝑏−𝑘 , 𝑒𝑚𝑖𝑛 ≤ 𝑒 ≤ 𝑒𝑚𝑎𝑥
𝑘=1
where:
Variable Meaning
𝑠 Sign, −1 or 1
𝑏 Base (radix), probably 2 on your system
𝑒 Exponent
𝑝 Precision: how many base-𝑏 digits in the number
𝑓𝑘 The individual digits of the number, the significand
Mode Description
-1 Indeterminable
0 Toward zero
1 To nearest
2 Toward positive infinity
3 Toward negative infinity… and beyond!
Unlike every other macro in this here header, FLT_ROUNDS might not be a constant expression.
Method Description
-1 Indeterminable
0 Evaluate all operations and constants to the precision of their respective types
1 Evaluate float and double operations as double and long double ops as long
double
2 Evaluate all operations and constants as long double
Value Description
-1 Indeterminable
0 Subnormals not supported for this type
1 Subnormals supported for this type
1
https://en.wikipedia.org/wiki/Subnormal_number
358 Chapter 47. <float.h> Floating Point Limits
1 #include <stdio.h>
2 #include <float.h>
3
4 int main(void)
5 {
6 float pi = 3.1415926535897932384626433832795028841971;
7
That’s the end, but stay tuned for the exciting conclusion of “How Many Decimal Places Can I Use?”
Because base 10 and base 2 (your typical FLT_RADIX) don’t mix very well, you can actually have more
than FLT_DIG in your float; the bits of storage go out a little farther. But these might round in a way
you don’t expect.
But if you want to convert a floating point number to base 10 and then be able to convert it back again
to the exact same floating point number, you’ll need FLT_DECIMAL_DIG digits from your float to make
sure you get those extra bits of storage represented. (And DBL_DECIMAL_DIG and LDBL_DECIMAL_DIG
for those corresponding types.)
Here’s some example output that shows how the value stored might have some extra decimal places at the
end.
1 #include <stdio.h>
2 #include <math.h>
3 #include <assert.h>
4 #include <float.h>
5
6 int main(void)
7 {
8 printf("FLT_DIG = %d\n", FLT_DIG);
9 printf("FLT_DECIMAL_DIG = %d\n\n", FLT_DECIMAL_DIG);
10
And the output on my machine, starting at 0.123456 and incrementing by 0.000001 each time:
FLT_DIG = 6
FLT_DECIMAL_DIG = 9
As written: 0.123456
As stored: 0.123456001
As written: 0.123457
As stored: 0.123457
47.6. Comprehensive Example 359
As written: 0.123458
As stored: 0.123457998
As written: 0.123459
As stored: 0.123458996
As written: 0.12346
As stored: 0.123459995
You can see that the value stored isn’t always the value we’re expecting since base-2 can’t represent all
base-10 fractions exactly. The best it can do is store more places and then round.
Also notice that even though we tried to stop the for loop before 0.123460, it actually ran including that
value since the stored version of that number was 0.123459995, which is still less than 0.123460.
Aren’t floating point numbers fun?
4 int main(void)
5 {
6 printf("FLT_RADIX: %d\n", FLT_RADIX);
7 printf("FLT_ROUNDS: %d\n", FLT_ROUNDS);
8 printf("FLT_EVAL_METHOD: %d\n", FLT_EVAL_METHOD);
9 printf("DECIMAL_DIG: %d\n\n", DECIMAL_DIG);
10
FLT_HAS_SUBNORM: 1
FLT_MANT_DIG: 24
FLT_DECIMAL_DIG: 9
FLT_DIG: 6
FLT_MIN_EXP: -125
FLT_MIN_10_EXP: -37
FLT_MAX_EXP: 128
FLT_MAX_10_EXP: 38
FLT_MIN: 1.175494351e-38
FLT_MAX: 3.402823466e+38
FLT_EPSILON: 1.192092896e-07
FLT_TRUE_MIN: 1.401298464e-45
DBL_HAS_SUBNORM: 1
DBL_MANT_DIG: 53
DBL_DECIMAL_DIG: 17
DBL_DIG: 15
DBL_MIN_EXP: -1021
DBL_MIN_10_EXP: -307
DBL_MAX_EXP: 1024
DBL_MAX_10_EXP: 308
DBL_MIN: 2.22507385850720138e-308
DBL_MAX: 1.79769313486231571e+308
DBL_EPSILON: 2.22044604925031308e-16
DBL_TRUE_MIN: 4.94065645841246544e-324
LDBL_HAS_SUBNORM: 1
LDBL_MANT_DIG: 64
LDBL_DECIMAL_DIG: 21
LDBL_DIG: 18
LDBL_MIN_EXP: -16381
LDBL_MIN_10_EXP: -4931
LDBL_MAX_EXP: 16384
LDBL_MAX_10_EXP: 4932
47.6. Comprehensive Example 361
LDBL_MIN: 3.362103143112093506263e-4932
LDBL_MAX: 1.189731495357231765021e+4932
LDBL_EPSILON: 1.084202172485504434007e-19
LDBL_TRUE_MIN: 3.645199531882474602528e-4951
sizeof(float): 4
sizeof(double): 8
sizeof(long double): 16
362 Chapter 47. <float.h> Floating Point Limits
Chapter 48
Function Description
imaxabs() Compute the absolute value of an intmax_t
imaxdiv() Compute the quotient and remainder of intmax_ts
strtoimax() Convert strings to type intmax_t
strtoumax() Convert strings to type uintmax_t
wcstoimax() Convert wide strings to type intmax_t
wcstoumax() Convert wide strings to type uintmax_t
This header does conversions to maximum sized integers, division with maximum sized integers, and also
provides format specifiers for printf() and scanf() for a variety of types defined in <stdint.h>.
The header <stdint.h> is included by this one.
48.1 Macros
These are to help with printf() and scanf() when you use a type such as int_least16_t… what
format specifiers do you use?
Let’s start with printf()—all these macros start with PRI and then are followed by the format specifier
you’d typically use for that type. Lastly, the number of bits is added on.
For example, the format specifier for a 64-bit integer is PRId64—the d is because you usually print integers
with "%d".
An unsigned 16-bit integer could be printed with PRIu16.
These macros expand to string literals. We can take advantage of the fact that C automatically concatenates
neighboring string literals and use these specifiers like this:
1 #include <stdio.h> // for printf()
2 #include <inttypes.h>
3
4 int main(void)
5 {
6 int16_t x = 32;
7
There’s nothing magical happening on line 8, above. Indeed, if I print out the value of the macro:
363
364 Chapter 48. <inttypes.h> More Integer Conversions
printf("%s\n", PRId16);
Here’s a table of all the macros you can use for printf() format specifiers… substitute the number of
bits for N, usually 8, 16, 32, or 64.
Note again how the lowercase center letter represents the usual format specifiers you’d pass to printf():
d, i, o, u, x, and X.
And we have a similar set of macros for scanf() for reading in these various types:
The rule is that for each type defined in <stdint.h> there will be corresponding printf() and scanf()
macros defined here.
48.2 imaxabs()
Compute the absolute value of an intmax_t
Synopsis
#include <inttypes.h>
Description
When you need the absolute value of the biggest integer type on the system, this is the function for you.
The spec notes that if the absolute value of the number cannot be represented, the behavior is undefined.
This would happen if you tried to take the absolute value of the smallest possible negative number in a
two’s-complement system.
Return Value
Returns the absolute value of the input, |𝑗|.
48.3. imaxdiv() 365
Example
1 #include <stdio.h>
2 #include <inttypes.h>
3
4 int main(void)
5 {
6 intmax_t j = -3490;
7
See Also
fabs()
48.3 imaxdiv()
Compute the quotient and remainder of intmax_ts
Synopsis
#include <inttypes.h>
Description
When you want to do integer division and remainder in a single operation, this function will do it for you.
It computes numer/denom and numer%denom and returns the result in a structure of type imaxdiv_t.
This structure has two imaxdiv_t fields, quot and rem, that you use to retrieve the sought-after values.
Return Value
Returns an imaxdiv_t containing the quotient and remainder of the operation.
Example
1 #include <stdio.h>
2 #include <inttypes.h>
3
4 int main(void)
5 {
6 intmax_t numer = INTMAX_C(3490);
7 intmax_t denom = INTMAX_C(17);
8
Output:
366 Chapter 48. <inttypes.h> More Integer Conversions
See Also
remquo()
Synopsis
#include <inttypes.h>
Description
These work just like the strtol() family of functions, except they return an intmax_t or uintmax_t.
See the strtol() reference page for details.
Return Value
Returns the converted string as an intmax_t or uintmax_t.
If the result is out of range, the returned value will be INTMAX_MAX, INTMAX_MIN, or UINTMAX_MAX, as
appropriate. And the errno variable will be set to ERANGE.
Example
The following example converts a base-10 number to an intmax_t. Then it attempts to convert an invalid
base-2 number, catching the error.
1 #include <stdio.h>
2 #include <inttypes.h>
3
4 int main(void)
5 {
6 intmax_t r;
7 char *endptr;
8
12 if (*endptr != '\0')
13 printf("Invalid digit: %c\n", *endptr);
14 else
15 printf("Value is %jd\n", r);
16
19
20 if (*endptr != '\0')
21 printf("Invalid digit: %c\n", *endptr);
22 else
23 printf("Value is %jd\n", r);
24 }
Output:
Value is 123456789012345
Invalid digit: 2
See Also
strtol(), errno
Synopsis
#include <stddef.h> // for wchar_t
#include <inttypes.h>
Description
These work just like the wcstol() family of functions, except they return an intmax_t or uintmax_t.
See the wcstol() reference page for details.
Return Value
Returns the converted wide string as an intmax_t or uintmax_t.
If the result is out of range, the returned value will be INTMAX_MAX, INTMAX_MIN, or UINTMAX_MAX, as
appropriate. And the errno variable will be set to ERANGE.
Example
The following example converts a base-10 number to an intmax_t. Then it attempts to convert an invalid
base-2 number, catching the error.
1 #include <wchar.h>
2 #include <inttypes.h>
3
4 int main(void)
5 {
6 intmax_t r;
7 wchar_t *endptr;
8
368 Chapter 48. <inttypes.h> More Integer Conversions
12 if (*endptr != '\0')
13 wprintf(L"Invalid digit: %lc\n", *endptr);
14 else
15 wprintf(L"Value is %jd\n", r);
16
20 if (*endptr != '\0')
21 wprintf(L"Invalid digit: %lc\n", *endptr);
22 else
23 wprintf(L"Value is %jd\n", r);
24 }
Value is 123456789012345
Invalid digit: 2
See Also
wcstol(), errno
Chapter 49
ISO-646 is a character encoding standard that’s very similar to ASCII. But it’s missing a few notable
characters, like |, ^, and ~.
Since these are operators or parts of operators in C, this header file defines a number of macros you can
use in case those characters aren’t found on your keyboard. (And also C++ can use these same alternate
spellings.)
Interestingly, there is no eq for ==, and & and ! are included despite being in ISO-646.
Example usage:
1 #include <stdio.h>
2 #include <iso646.h>
3
4 int main(void)
5 {
6 int x = 12;
7 int y = 30;
8
I’ve personally never seen this file included, but I’m sure it gets used from time to time.
369
370 Chapter 49. <iso646.h> Alternative Operator Spellings
Chapter 50
Important note: the “minimum magnitude” in the table below is the minimum allowed by the spec. It’s
very likely that the values on your bad-ass system exceed those, below.
371
372 Chapter 50. <limits.h> Numeric Limits
1 #include <stdio.h>
2 #include <limits.h>
3
4 int main(void)
5 {
6 printf("chars are %ssigned\n", CHAR_MIN == 0? "un": "");
7 }
4 int main(void)
5 {
6 printf("CHAR_BIT = %d\n", CHAR_BIT);
7 printf("SCHAR_MIN = %d\n", SCHAR_MIN);
8 printf("SCHAR_MAX = %d\n", SCHAR_MAX);
9 printf("UCHAR_MAX = %d\n", UCHAR_MAX);
10 printf("CHAR_MIN = %d\n", CHAR_MIN);
11 printf("CHAR_MAX = %d\n", CHAR_MAX);
12 printf("MB_LEN_MAX = %d\n", MB_LEN_MAX);
13 printf("SHRT_MIN = %d\n", SHRT_MIN);
14 printf("SHRT_MAX = %d\n", SHRT_MAX);
15 printf("USHRT_MAX = %u\n", USHRT_MAX);
16 printf("INT_MIN = %d\n", INT_MIN);
17 printf("INT_MAX = %d\n", INT_MAX);
18 printf("UINT_MAX = %u\n", UINT_MAX);
19 printf("LONG_MIN = %ld\n", LONG_MIN);
20 printf("LONG_MAX = %ld\n", LONG_MAX);
2
https://en.wikipedia.org/wiki/Two%27s_complement
50.4. Demo Program 373
Looks like my system probably uses two’s-complement encoding for signed numbers, my chars are
signed, and my ints are 32-bit.
374 Chapter 50. <limits.h> Numeric Limits
Chapter 51
Function Description
setlocale() Set the locale
localeconv() Get information about the current locale
The “locale” is the details of how the program should run given its physical location on the planet.
For example, in one locale, a unit of money might be printed as $123, and in another €123.
Or one locale might use ASCII encoding and another UTF-8 encoding.
By default, the program runs in the “C” locale. It has a basic set of characters with a single-byte encoding.
If you try to print UTF-8 characters in the C locale, nothing will print. You have to switch to a proper
locale.
51.1 setlocale()
Set the locale
Synopsis
#include <locale.h>
Description
Sets the locale for the given category.
Category is one of the following:
Category Description
LC_ALL All of the following categories
LC_COLLATE Affects the strcoll() and strxfrm() functions
LC_CTYPE Affects the functions in <ctype.h>
LC_MONETARY Affects the monetary information returned from
localeconv()
375
376 Chapter 51. <locale.h> locale handling
Category Description
LC_NUMERIC Affects the decimal point for formatted I/O and
formatted string functions, and the monetary
information returned from localeconv()
LC_TIME Affects the strftime() and wcsftime()
functions
And there are three portable things you can pass in for locale; any other string passed in is
implementation-defined and non-portable.
Locale Description
"C" Set the program to the C locale
"" (Empty string) Set the program to the native locale
of this system
NULL Change nothing; just return the current locale
Other Set the program to an implementation-defined
locale
setlocale(LC_ALL, "");
Handily, setlocale() returns the locale that was just set, so you could see what the actual locale is on
your system.
Return Value
On success, returns a pointer to the string representing the current locale. You may not modify this string,
and it might be changed by subsequent calls to setlocale().
On failure, returns NULL.
Example
Here we get the current locale. Then we set it to the native locale, and print out what that is.
1 #include <stdio.h>
2 #include <locale.h>
3
4 int main(void)
5 {
6 char *loc;
7
Output on my system:
51.2. localeconv() 377
Starting locale: C
Native locale: en_US.UTF-8
Note that my native locale (on a Linux box) might be different from what you see.
Nevertheless, I can explicitly set it on my system without a problem, or to any other locale I have installed:
13 loc = setlocale(LC_ALL, "en_US.UTF-8"); // Non-portable
See Also
localeconv(), strcoll(), strxfrm(), strftime(), wcsftime(), printf(), scanf(), <ctype.h>
51.2 localeconv()
Get information about the current locale
Synopsis
#include <locale.h>
Description
This function just returns a pointer to a struct lconv, but is still a bit of a powerhouse.
The returned structure contains tons of information about the locale. Here are the fields of struct lconv
and their meanings.
First, some conventions. In the field names, below, a _p_ means “positive”, and _n_ means “negative”,
and int_ means “international”. Though a lot of these are type char or char*, most (or the strings they
point to) are actually treated as integers1 .
Before we go further, know that CHAR_MAX (from <limits.h>) is the maximum value that can be held in
a char. And that many of the following char values use that to indicate the value isn’t available in the
given locale.
Field Description
char *mon_decimal_point Decimal pointer character for money, e.g. ".".
char *mon_thousands_sep Thousands separator character for money, e.g. ",".
char *mon_grouping Grouping description for money (see below).
char *positive_sign Positive sign for money, e.g. "+" or "".
char *negative_sign Negative sign for money, e.g. "-".
char *currency_symbol Currency symbol, e.g. "$".
char frac_digits When printing monetary amounts, how many digits to print past the
decimal point, e.g. 2.
char p_cs_precedes 1 if the currency_symbol comes before the value for a non-negative
monetary amount, 0 if after.
char n_cs_precedes 1 if the currency_symbol comes before the value for a negative
monetary amount, 0 if after.
char p_sep_by_space Determines the separation of the currency symbol from the value
for non-negative amounts (see below).
1
Remember that char is just a byte-sized integer.
378 Chapter 51. <locale.h> locale handling
Field Description
char n_sep_by_space Determines the separation of the currency symbol from the value
for negative amounts (see below).
char p_sign_posn Determines the positive_sign position for non-negative values.
char p_sign_posn Determines the positive_sign position for negative values.
char *int_curr_symbol International currency symbol, e.g. "USD ".
char int_frac_digits International value for frac_digits.
char int_p_cs_precedes International value for p_cs_precedes.
char int_n_cs_precedes International value for n_cs_precedes.
char int_p_sep_by_space International value for p_sep_by_space.
char int_n_sep_by_space International value for n_sep_by_space.
char int_p_sign_posn International value for p_sign_posn.
char int_n_sign_posn International value for n_sign_posn.
Even though many of these have char type, the value stored within is meant to be accessed as an integer.
All the sep_by_space variants deal with spacing around the currency sign. Valid values are:
Value Description
0 No space between currency symbol and value.
1 Separate the currency symbol (and sign, if any) from the value with a space.
2 Separate the sign symbol from the currency symbol (if adjacent) with a
space, otherwise separate the sign symbol from the value with a space.
Value Description
0 Put parens around the value and the currency symbol.
1 Put the sign string in front of the currency symbol and value.
2 Put the sign string after the currency symbol and value.
3 Put the sign string directly in front of the currency symbol.
4 Put the sign string directly behind the currency symbol.
For more information on the mon_grouping field, see “Monetary Digit Grouping” in the “Locale and
Internationalization” chapter.
Return Value
Returns a pointer to the structure containing the locale information.
The program may not modify this structure.
Subsequent calls to localeconv() may overwrite this structure, as might calls to setlocale() with
LC_ALL, LC_MONETARY, or LC_NUMERIC.
Example
Here’s a program to print the locale information for the native locale.
1 #include <stdio.h>
2 #include <locale.h>
3 #include <limits.h> // for CHAR_MAX
4
7 int done = 0;
8
9 while (!done) {
10 if (*mg == CHAR_MAX)
11 printf("CHAR_MAX ");
12 else
13 printf("%c ", *mg + '0');
14 done = *mg == CHAR_MAX || *mg == 0;
15 mg++;
16 }
17 }
18
19 int main(void)
20 {
21 setlocale(LC_ALL, "");
22
Output on my system:
mon_decimal_point : .
mon_thousands_sep : ,
mon_grouping : 3 3 0
positive_sign :
negative_sign : -
currency_symbol : $
frac_digits : 2
p_cs_precedes : 1
n_cs_precedes : 1
p_sep_by_space : 0
n_sep_by_space : 0
p_sign_posn : 1
p_sign_posn : 1
380 Chapter 51. <locale.h> locale handling
int_curr_symbol : USD
int_frac_digits : 2
int_p_cs_precedes : 1
int_n_cs_precedes : 1
int_p_sep_by_space: 1
int_n_sep_by_space: 1
int_p_sign_posn : 1
int_n_sign_posn : 1
See Also
setlocale()
Chapter 52
<math.h> Mathematics
Many of the following functions have float and long double variants as described below (e.g. pow(),
powf(), powl()). The float and long double variants are omitted from the following table to keep
your eyeballs from melting out.
Function Description
acos() Calculate the arc cosine of a number.
acosh() Compute arc hyperbolic cosine.
asin() Calculate the arc sine of a number.
asinh() Compute arc hyperbolic sine.
atan(), atan2() Calculate the arc tangent of a number.
atanh() Compute the arc hyperbolic tangent.
cbrt() Compute the cube root.
ceil() Ceiling—return the next whole number not smaller than the given number.
copysign() Copy the sign of one value into another.
cos() Calculate the cosine of a number.
cosh() Compute the hyperbolic cosine.
erf() Compute the error function of the given value.
erfc() Compute the complementary error function of a value.
exp() Compute 𝑒 raised to a power.
exp2() Compute 2 to a power.
expm1() Compute 𝑒𝑥 − 1.
fabs() Compute the absolute value.
fdim() Return the positive difference between two numbers clamped at 0.
floor() Compute the largest whole number not larger than the given value.
fma() Floating (AKA “Fast”) multiply and add.
fmax(), fmin() Return the maximum or minimum of two numbers.
fmod() Compute the floating point remainder.
fpclassify() Return the classification of a given floating point number.
frexp() Break a number into its fraction part and exponent (as a power of 2).
hypot() Compute the length of the hypotenuse of a triangle.
ilogb() Return the exponent of a floating point number.
isfinite() True if the number is not infinite or NaN.
isgreater() True if one argument is greater than another.
isgreatereequal() True if one argument is greater than or equal to another.
isinf() True if the number is infinite.
isless() True if one argument is less than another.
islesseequal() True if one argument is less than or equal to another.
islessgreater() Test if a floating point number is less than or greater than another.
isnan() True if the number is Not-a-Number.
isnormal() True if the number is normal.
isunordered() Macro returns true if either floating point argument is NaN.
381
382 Chapter 52. <math.h> Mathematics
Function Description
ldexp() Multiply a number by an integral power of 2.
lgamma() Compute the natural logarithm of the absolute value of Γ(𝑥).
log() Compute the natural logarithm.
log10() Compute the log-base-10 of a number.
log2() Compute the base-2 logarithm of a number.
logb() Extract the exponent of a number given FLT_RADIX.
log1p() Compute the natural logarithm of a number plus 1.
lrint() Returns x rounded in the current rounding direction as an integer.
lround(), llround() Round a number in the good old-fashioned way, returning an integer.
modf() Extract the integral and fractional parts of a number.
nan() Return NAN.
nearbyint() Rounds a value in the current rounding direction.
nextafter() Get the next (or previous) representable floating point value.
nexttoward() Get the next (or previous) representable floating point value.
pow() Compute a value raised to a power.
remainder() Compute the remainder IEC 60559-style.
remquo() Compute the remainder and (some of the) quotient.
rint() Rounds a value in the current rounding direction.
round() Round a number in the good old-fashioned way.
scalbn(), scalbln() Efficiently compute 𝑥 × 𝑟𝑛 , where 𝑟 is FLT_RADIX.
signbit() Return the sign of a number.
sin() Calculate the sine of a number.
sqrt() Calculate the square root of a number.
tan() Calculate the tangent of a number.
tanh() Compute the hyperbolic tangent.
tgamma() Compute the gamma function, Γ(𝑥).
trunc() Truncate the fractional part off a floating point value.
It’s your favorite subject: Mathematics! Hello, I’m Doctor Math, and I’ll be making math FUN and
EASY!
[vomiting sounds]
Ok, I know math isn’t the grandest thing for some of you out there, but these are merely functions that
quickly and easily do math you either know, want, or just don’t care about. That pretty much covers it.
Remember that parameters are given values as if you assigned into them. So if you pass a double to
powf(), it’ll choose the closest float it can to hold the double. If the double doesn’t fit, undefined
behavior happens.
• float_t
• double_t
The float_t type is at least as accurate as a float, and the double_t type is at least as accurate as a
double.
The idea with these types is they can represent the most efficient way of storing numbers for maximum
speed.
Their actual types vary by implementation, but can be determined by the value of the FLT_EVAL_METHOD
macro.
For all defined values of FLT_EVAL_METHOD, float_t is the least-precise type used for all floating cal-
culations.
Defined in <float.h> is FLT_RADIX: the number base used by floating point numbers. This is commonly
2, but could be anything.
1
Though the system defines MATH_ERRNO as 1 and MATH_ERREXCEPT as 2, it’s best to always use their symbolic names. Just in
case.
384 Chapter 52. <math.h> Mathematics
math_errhandling Description
MATH_ERRNO The system uses errno for math errors.
MATH_ERREXCEPT The system uses exceptions for math errors.
MATH_ERRNO | MATH_ERREXCEPT The system does both! (That’s a bitwise-OR!)
If you do this at global scope, it stays at whatever state you set it to until you change it.
If you do it at block scope, it reverts to the value outside the block when the block ends.
The initial value of the FP_CONTRACT pragma varies from system to system.
52.6 fpclassify()
Return the classification of a given floating point number.
Synopsis
#include <math.h>
Description
What kind of entity does this floating point number represent? What are the options?
We’re used to floating point numbers being regular old things like 3.14 or 3490.0001.
52.6. fpclassify() 385
But floating point numbers can also represent things like infinity. Or Not-A-Number (NAN). This function
will let you know which type of floating point number the argument is.
This is a macro, so you can use it with float, double, long double or anything similar.
Return Value
Returns one of these macros depending on the argument’s classification:
Classification Description
FP_INFINITE Number is infinite.
FP_NAN Number is Not-A-Number (NAN).
FP_NORMAL Just a regular number.
FP_SUBNORMAL Number is a sub-normal number.
FP_ZERO Number is zero.
A discussion of subnormal numbers is beyond the scope of the guide, and is something that most devs
go their whole lives without dealing with. In a nutshell, it’s a way to represent really small numbers that
might normally round down to zero. If you want to know more, see the Wikipedia page on denormal
numbers2 .
Example
Print various number classifications.
1 #include <stdio.h>
2 #include <math.h>
3
14 return "unknown";
15 }
16
17 int main(void)
18 {
19 printf(" 1.23: %s\n", get_classification(1.23));
20 printf(" 0.0: %s\n", get_classification(0.0));
21 printf("sqrt(-1): %s\n", get_classification(sqrt(-1)));
22 printf("1/tan(0): %s\n", get_classification(1/tan(0)));
23 printf(" 1e-310: %s\n", get_classification(1e-310)); // very small!
24 }
Output3 :
1.23: normal
0.0: zero
sqrt(-1): not a number
2
https://en.wikipedia.org/wiki/Denormal_number
3
This is on my system. Some systems will have different points at which numbers become subnormal, or they might not support
subnormal values at all.
386 Chapter 52. <math.h> Mathematics
1/tan(0): infinity
1e-310: subnormal
See Also
isfinite(), isinf(), isnan(), isnormal(), signbit()
Synopsis
#include <math.h>
Description
These are helper macros to fpclassify(). Bring macros, they work on any floating point type.
Macro Description
isfinite() True if the number is not infinite or NaN.
isinf() True if the number is infinite.
isnan() True if the number is Not-a-Number.
isnormal() True if the number is normal.
For more superficial discussion on normal and subnormal numbers, see fpclassify().
Return Value
Returns non-zero for true, and zero for false.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf(" isfinite(1.23): %d\n", isfinite(1.23)); // 1
7 printf(" isinf(1/tan(0)): %d\n", isinf(1/tan(0))); // 1
8 printf(" isnan(sqrt(-1)): %d\n", isnan(sqrt(-1))); // 1
9 printf("isnormal(1e-310): %d\n", isnormal(1e-310)); // 0
10 }
52.8. signbit() 387
See Also
fpclassify(), signbit(),
52.8 signbit()
Return the sign of a number.
Synopsis
#include <math.h>
Description
This macro takes any floating point number and returns a value indicating the sign of the number, positive
or negative.
Return Value
Returns 1 if the sign is negative, otherwise 0.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%d\n", signbit(3490.0)); // 0
7 printf("%d\n", signbit(-37.0)); // 1
8 }
See Also
fpclassify(), isfinite(), isinf(), isnan(), isnormal(), copysign()
Synopsis
#include <math.h>
Description
Calculates the arc cosine of a number in radians. (That is, the value whose cosine is x.) The number must
be in the range -1.0 to 1.0.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
Returns the arc cosine of x, unless x is out of range. In that case, errno will be set to EDOM and the
return value will be NaN. The variants return different types.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double acosx;
7 long double ldacosx;
8
9 acosx = acos(0.2);
10 ldacosx = acosl(0.3L);
11
12 printf("%f\n", acosx);
13 printf("%Lf\n", ldacosx);
14 }
See Also
asin(), atan(), atan2(), cos()
Synopsis
#include <math.h>
Description
Calculates the arc sine of a number in radians. (That is, the value whose sine is x.) The number must be
in the range -1.0 to 1.0.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
52.11. atan(), atanf(), atanl(), atan2(), atan2f(), atan2l() 389
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
Returns the arc sine of x, unless x is out of range. In that case, errno will be set to EDOM and the return
value will be NaN. The variants return different types.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double asinx;
7 long double ldasinx;
8
9 asinx = asin(0.2);
10 ldasinx = asinl(0.3L);
11
12 printf("%f\n", asinx);
13 printf("%Lf\n", ldasinx);
14 }
See Also
acos(), atan(), atan2(), sin()
Synopsis
#include <math.h>
Description
Calculates the arc tangent of a number in radians. (That is, the value whose tangent is x.)
The atan2() variants are pretty much the same as using atan() with y/x as the argument…except that
atan2() will use those values to determine the correct quadrant of the result.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
390 Chapter 52. <math.h> Mathematics
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
The atan() functions return the arc tangent of x, which will be between PI/2 and -PI/2. The atan2()
functions return an angle between PI and -PI.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double atanx;
7 long double ldatanx;
8
9 atanx = atan(0.7);
10 ldatanx = atanl(0.3L);
11
12 printf("%f\n", atanx);
13 printf("%Lf\n", ldatanx);
14
18 printf("%f\n", atanx);
19 printf("%Lf\n", ldatanx);
20 }
See Also
tan(), asin(), atan()
Synopsis
#include <math.h>
double cos(double x)
float cosf(float x)
long double cosl(long double x)
Description
Calculates the cosine of the value x, where x is in radians.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
52.13. sin(), sinf(), sinl() 391
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
Returns the cosine of x. The variants return different types.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double cosx;
7 long double ldcosx;
8
12 printf("%f\n", cosx);
13 printf("%Lf\n", ldcosx);
14 }
See Also
sin(), tan(), acos()
Synopsis
#include <math.h>
Description
Calculates the sine of the value x, where x is in radians.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
Returns the sine of x. The variants return different types.
392 Chapter 52. <math.h> Mathematics
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double sinx;
7 long double ldsinx;
8
12 printf("%f\n", sinx);
13 printf("%Lf\n", ldsinx);
14 }
See Also
cos(), tan(), asin()
Synopsis
#include <math.h>
double tan(double x)
float tanf(float x)
long double tanl(long double x)
Description
Calculates the tangent of the value x, where x is in radians.
For those of you who don’t remember, radians are another way of measuring an angle, just like degrees.
To convert from degrees to radians or the other way around, use the following code:
pi = 3.14159265358979;
degrees = radians * 180 / pi;
radians = degrees * pi / 180;
Return Value
Returns the tangent of x. The variants return different types.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
52.15. acosh(), acoshf(), acoshl() 393
6 double tanx;
7 long double ldtanx;
8
12 printf("%f\n", tanx);
13 printf("%Lf\n", ldtanx);
14 }
See Also
sin(), cos(), atan(), atan2()
Synopsis
#include <math.h>
Description
Trig lovers can rejoice! C has arc hyperbolic cosine!
These functions return the nonnegative acosh of x, which must be greater than or equal to 1.
Return Value
Returns the arc hyperbolic cosince in the range [0, +∞].
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("acosh 1.8 = %f\n", acosh(1.8)); // 1.192911
7 }
See Also
asinh()
394 Chapter 52. <math.h> Mathematics
Synopsis
#include <math.h>
Description
Trig lovers can rejoice! C has arc hyperbolic sine!
Return Value
Returns the arc hyperbolic sine.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("asinh 1.8 = %f\n", asinh(1.8)); // 1.350441
7 }
See Also
acosh()
Synopsis
#include <math.h>
Description
These functions compute the arc hyperbolic tangent of x, which must be in the range [−1, +1]. Passing
exactly −1 or +1 might result in a pole error.
Return Value
Returns the arc hyperbolic tangent of x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("atanh 0.5 = %f\n", atanh(0.5)); // 0.549306
7 }
See Also
acosh(), asinh()
Synopsis
#include <math.h>
Description
These functions predictably compute the hyperbolic cosine of x. A range error might occur if x is too
large.
Return Value
Returns the hyperbolic cosine of x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("cosh 0.5 = %f\n", cosh(0.5)); // 1.127626
7 }
396 Chapter 52. <math.h> Mathematics
See Also
sinh(), tanh()
Synopsis
#include <math.h>
Description
These functions predictably compute the hyperbolic sine of x. A range error might occur if x is too large.
Return Value
Returns the hyperbolic sine of x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("sinh 0.5 = %f\n", sinh(0.5)); // 0.521095
7 }
See Also
sinh(), tanh()
Synopsis
#include <math.h>
Description
These functions predictably compute the hyperbolic tangent of x.
Mercifully, this is the last trig-related man page I’m going to write.
Return Value
Returns the hyperbolic tangent of x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("tanh 0.5 = %f\n", tanh(0.5)); // 0.462117
7 }
See Also
cosh(), sinh()
Synopsis
#include <math.h>
Description
Compute 𝑒𝑥 where 𝑒 is Euler’s number4 .
The number 𝑒 is named after Leonard Euler, born April 15, 1707, who is responsible, among other things,
for making this reference page longer than it needed to be.
Return Value
Returns 𝑒𝑥 .
Example
1 #include <stdio.h>
2 #include <math.h>
3
4
https://en.wikipedia.org/wiki/E_(mathematical_constant)
398 Chapter 52. <math.h> Mathematics
4 int main(void)
5 {
6 printf("exp(1) = %f\n", exp(1)); // 2.718282
7 printf("exp(2) = %f\n", exp(2)); // 7.389056
8 }
See Also
exp2(), expm1(), pow(), log()
Synopsis
#include <math.h>
Description
These functions raise 2 to a power. Very exciting, since computers are all about twos-to-powers!
These are likely to be faster than using pow() to do the same thing.
They support fractional exponents, as well.
A range error occurs if x is too large.
Return Value
exp2() returns 2𝑥 .
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("2^3 = %f\n", exp2(3)); // 2^3 = 8.000000
7 printf("2^8 = %f\n", exp2(8)); // 2^8 = 256.000000
8 printf("2^0.5 = %f\n", exp2(0.5)); // 2^0.5 = 1.414214
9 }
See Also
exp(), pow()
52.23. expm1(), expm1f(), expm1l() 399
Synopsis
#include <math.h>
Description
This is just like exp() except—plot twist!–it computes that result minus one.
For more discussion about what 𝑒 is, see the exp() man page.
If x is giant, a range error might occur.
For small values of x near zero, expm1(x) might be more accurate than computing exp(x)-1.
Return Value
Returns 𝑒𝑥 − 1.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", expm1(2.34)); // 9.381237
7 }
See Also
exp()
Synopsis
#include <math.h>
Description
If you have a floating point number, you can break it into its fractional part and exponent part (as a power
of 2).
For example, if you have the number 1234.56, this can be represented as a multiple of a power of 2 like
so:
As for why, I have a simple answer: I don’t know. I can’t find a use. K&R2 and everyone else I can find
just says how to use it, but not why you might want to.
The functions frexp, ldexp, and modf are primitives used by the remainder of the library.
There was some sentiment for dropping them for the same reasons that ecvt, fcvt, and gcvt
were dropped, but their adherents rescued them for general use. Their use is problematic: on
non-binary architectures, ldexp may lose precision and frexp may be inefficient.
Return Value
frexp() returns the fractional part of value in the range 0.5 (inclusive) to 1 (exclusive), or 0. And it
stores the exponent power-of-2 in the variable pointed to by exp.
If you pass in zero, the return value and the variable exp points to are both zero.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double frac;
7 int expt;
8
Output:
1234.56 = 0.6028125 x 2^11
See Also
ldexp(), ilogb(), modf()
Synopsis
#include <math.h>
Description
This gives you the exponent of the given number… it’s a little weird, because the exponent depends on
the value of FLT_RADIX. Now, this is very often 2—but no guarantees!
It actually returns log𝑟 |𝑥| where 𝑟 is FLT_RADIX.
Domain or range errors might occur for invalid values of x, or for return values that are outside the range
of the return type.
Return Value
The exponent of the absolute value of the given number, depending on FLT_RADIX.
Specifically log𝑟 |𝑥| where 𝑟 is FLT_RADIX.
If you pass in 0, it’ll return FP_ILOGB0.
If you pass in infinity, it’ll return INT_MAX.
If you pass in NaN, it’ll return FP_ILOGBNAN.
The spec goes on to say that the value of FP_ILOGB0 will be either INT_MIN or -INT_MAX. And the value
of FP_ILOGBNAN shall be either INT_MAX or INT_MIN, if that’s useful in any way.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%d\n", ilogb(257)); // 8
7 printf("%d\n", ilogb(256)); // 8
8 printf("%d\n", ilogb(255)); // 7
9 }
See Also
frexp(), logb()
Synopsis
402 Chapter 52. <math.h> Mathematics
#include <math.h>
Description
These functions multiply the given number x by 2 raised to the exp power.
Return Value
Returns 𝑥 × 2𝑒𝑥𝑝 .
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("1 x 2^10 = %f\n", ldexp(1, 10));
7 printf("5.67 x 2^7 = %f\n", ldexp(5.67, 7));
8 }
Output:
1 x 2^10 = 1024.000000
5.67 x 2^7 = 725.760000
See Also
exp()
Synopsis
#include <math.h>
Description
Natural logarithms! And there was much rejoycing.
These compute the base-𝑒 logarithm of a number, log𝑒 𝑥, ln 𝑥.
52.28. log10(), log10f(), log10l() 403
Return Value
The base-𝑒 logarithm of the given value, log𝑒 𝑥, ln 𝑥.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 const double e = 2.718281828459045;
7
See Also
exp(), log10(), log1p()
Synopsis
#include <math.h>
Description
Just when you thought you might have to use Laws of Logarithms to compute this, here’s a function
coming out of the blue to save you.
These compute the base-10 logarithm of a number, log10 𝑥.
In other words, for a given 𝑥, solves 𝑥 = 10𝑦 for 𝑦.
Return Value
Returns the log base-10 of x, log10 𝑥.
Example
1 #include <stdio.h>
2 #include <math.h>
3
404 Chapter 52. <math.h> Mathematics
4 int main(void)
5 {
6 printf("%f\n", log10(3490.2)); // 3.542850
7 printf("%f\n", log10(10)); // 1.000000
8 }
See Also
pow(), log()
Synopsis
#include <math.h>
Description
This computes log𝑒 (1 + 𝑥), ln(1 + 𝑥).
This works just like calling:
log(1 + x)
Return Value
Returns log𝑒 (1 + 𝑥), ln(1 + 𝑥).
Example
Compute some big and small logarithm values to see the difference between log1p() and log():
1 #include <stdio.h>
2 #include <float.h> // for LDBL_DECIMAL_DIG
3 #include <math.h>
4
5 int main(void)
6 {
7 printf("Big log1p() : %.*Lf\n", LDBL_DECIMAL_DIG-1, log1pl(9));
8 printf("Big log() : %.*Lf\n", LDBL_DECIMAL_DIG-1, logl(1 + 9));
9
Output on my system:
Big log1p() : 2.30258509299404568403
Big log() : 2.30258509299404568403
Small log1p(): 0.00995033085316808305
Small log() : 0.00995033085316809164
See Also
log()
Synopsis
#include <math.h>
Description
Wow! Were you thinking we were done with the logarithm functions? We’re only getting started!
Return Value
Returns the base-2 logarithm of the given value, log2 𝑥.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", log2(3490.2)); // 11.769094
7 printf("%f\n", log2(256)); // 8.000000
8 }
See Also
log()
406 Chapter 52. <math.h> Mathematics
Synopsis
#include <math.h>
Description
This function returns the whole number portion of the exponent of the number with radix FLT_RADIX,
namely the whole number portion log𝑟 |𝑥| where 𝑟 is FLT_RADIX. Fractional numbers are truncated.
Return Value
This function returns the whole number portion of log𝑟 |𝑥| where 𝑟 is FLT_RADIX.
Example
1 #include <stdio.h>
2 #include <float.h> // For FLT_RADIX
3 #include <math.h>
4
5 int main(void)
6 {
7 printf("FLT_RADIX = %d\n", FLT_RADIX);
8 printf("%f\n", logb(3490.2));
9 printf("%f\n", logb(256));
10 }
Output:
FLT_RADIX = 2
11.000000
8.000000
See Also
ilogb()
Synopsis
#include <math.h>
Description
If you have a floating point number, like 123.456, this function will extract the integral part (123.0) and
the fractional part (0.456). It’s total coincidence that this is exactly the plot for the latest Jason Statham
action spectacular.
Both the integral part and fractional parts keep the sign of the passed in value.
Return Value
These functions return the fractional part of the number. The integral part is stored in the address pointed
to by iptr. Both the integral and fractional parts preserve the sign of the passed-in value.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 void print_parts(double x)
5 {
6 double i, f;
7
8 f = modf(x, &i);
9
15 int main(void)
16 {
17 print_parts(123.456);
18 print_parts(-123.456);
19 }
Output:
Entire number : 123.456000
Integral part : 123.000000
Fractional part: 0.456000
See Also
frexp()
Synopsis
#include <math.h>
Description
These functions efficiently compute 𝑥 × 𝑟𝑛 , where 𝑟 is FLT_RADIX.
The name of this function should have an obvious meaning to you. Clearly they all start with the prefix
“scalb” which means…
Suffix Meaning
n scalbn()—exponent n is an int
nf scalbnf()—float version of scalbn()
nl scalbnl()—long double version of scalbn()
ln scalbln()—exponent n is a long int
lnf scalblnf()—float version of scalbln()
lnl scalblnl()—long double version of scalbln()
So while I’m still in the dark about “scalb”, at least I have that part down.
Return Value
Returns 𝑥 × 𝑟𝑛 , where 𝑟 is FLT_RADIX.
52.34. cbrt(), cbrtf(), cbrtl() 409
Example
1 #include <stdio.h>
2 #include <math.h>
3 #include <float.h>
4
5 int main(void)
6 {
7 printf("FLT_RADIX = %d\n\n", FLT_RADIX);
8 printf("scalbn(3, 8) = %f\n", scalbn(2, 8));
9 printf("scalbnf(10.2, 20) = %f\n", scalbnf(10.2, 20));
10 }
Output on my system:
FLT_RADIX = 2
scalbn(3, 8) = 512.000000
scalbn(10.2, 20.7) = 10695475.200000
See Also
exp2(), pow()
Synopsis
#include <math.h>
Description
√
Computes the cube root of x, 𝑥1/3 , 3
𝑥.
Return Value
√
Returns the cube root of x, 𝑥1/3 , 3
𝑥.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("cbrt(1729.03) = %f\n", cbrt(1729.03));
7 }
410 Chapter 52. <math.h> Mathematics
Output:
cbrt(1729.03) = 12.002384
See Also
sqrt(), pow()
Synopsis
#include <math.h>
Description
These functions straightforwardly return the absolute value of x, that is |𝑥|.
If you’re rusty on your absolute values, all it means is that the result will be positive, even if x is negative.
It’s just strips negative signs off.
Return Value
Returns the absolute value of x, |𝑥|.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("fabs(3490.0) = %f\n", fabs(3490.0)); // 3490.000000
7 printf("fabs(-3490.0) = %f\n", fabs(3490.0)); // 3490.000000
8 }
See Also
abs(), copysign(), imaxabs()
Synopsis
#include <math.h>
Description
Pythagorean Theorem6 fans rejoice! This is the function you’ve been waiting for!
If you know the lengths of the two sides of a right triangle, x and y, you can compute the length of the
hypotenuse (the longest, diagonal side) with this function.
In particular, it computes the square root of the sum of the squares of the sides: √𝑥2 + 𝑦 2 .
Return Value
Returns the lenght of the hypotenuse of a right triangle with side lengths x and y: √𝑥2 + 𝑦 2 .
Example
1 printf("%f\n", hypot(3, 4)); // 5.000000
See Also
sqrt()
Synopsis
#include <math.h>
Description
Computes x raised to the yth power: 𝑥𝑦 .
6
https://en.wikipedia.org/wiki/Pythagorean_theorem
412 Chapter 52. <math.h> Mathematics
Return Value
Returns x raised to the yth power: 𝑥𝑦 .
Example
1 printf("%f\n", pow(3, 4)); // 3^4 = 81.000000
2 printf("%f\n", pow(2, 0.5)); // sqrt 2 = 1.414214
See Also
exp(), exp2(), sqrt(), cbrt()
52.38 sqrt()
Calculate the square root of a number.
Synopsis
#include <math.h>
Description
√
Computes the square root of a number: 𝑥. To those of you who don’t know what a square root is, I’m
not going to explain. Suffice it to say, the square root of a number delivers a value that when squared
(multiplied by itself) results in the original number.
Ok, fine—I did explain it after all, but only because I wanted to show off. It’s not like I’m giving you
examples or anything, such as the square root of nine is three, because when you multiply three by three
you get nine, or anything like that. No examples. I hate examples!
And I suppose you wanted some actual practical information here as well. You can see the usual trio of
functions here—they all compute square root, but they take different types as arguments. Pretty straight-
forward, really.
Return Value
√
Returns (and I know this must be something of a surprise to you) the square root of x: 𝑥.
52.39. erf(), erff(), erfl() 413
Example
1 // example usage of sqrt()
2
11 dx = x2 - x1;
12 dy = y2 - y1;
13 printf("distance between points (x1, y1) and (x2, y2): %.2f\n",
14 sqrt(dx*dx + dy*dy));
See Also
hypot(), pow()
Synopsis
#include <math.h>
Description
These functions compute the error function7 of a value.
Return Value
Returns the error function of x:
𝑥
2 2
√ ∫ 𝑒−𝑡 𝑑𝑡
𝜋 0
Example
1 for (float i = -2; i <= 2; i += 0.5)
2 printf("% .1f: %f\n", i, erf(i));
7
https://en.wikipedia.org/wiki/Error_function
414 Chapter 52. <math.h> Mathematics
Output:
-2.0: -0.995322
-1.5: -0.966105
-1.0: -0.842701
-0.5: -0.520500
0.0: 0.000000
0.5: 0.520500
1.0: 0.842701
1.5: 0.966105
2.0: 0.995322
See Also
erfc()
Synopsis
#include <math.h>
Description
These functions compute the complementary error function8 of a value.
This is the same as:
1 - erf(x)
Return Value
Returns 1 - erf(x), namely:
∞
2 2
√ ∫ 𝑒−𝑡 𝑑𝑡
𝜋 𝑥
Example
1 for (float i = -2; i <= 2; i += 0.5)
2 printf("% .1f: %f\n", i, erfc(i));
Output:
8
https://en.wikipedia.org/wiki/Error_function
52.41. lgamma(), lgammaf(), lgammal() 415
-2.0: 1.995322
-1.5: 1.966105
-1.0: 1.842701
-0.5: 1.520500
0.0: 1.000000
0.5: 0.479500
1.0: 0.157299
1.5: 0.033895
2.0: 0.004678
See Also
erf()
Synopsis
#include <math.h>
Description
Compute the natural log of the absolute value of gamma9 x, log𝑒 |Γ(𝑥)|.
A range error can occur if x is too large.
A pole error can occur is x is non-positive.
Return Value
Returns log𝑒 |Γ(𝑥)|.
Example
1 for (float i = 0.5; i <= 4; i += 0.5)
2 printf("%.1f: %f\n", i, lgamma(i));
Output:
0.5: 0.572365
1.0: 0.000000
1.5: -0.120782
2.0: 0.000000
2.5: 0.284683
3.0: 0.693147
3.5: 1.200974
4.0: 1.791759
9
https://en.wikipedia.org/wiki/Gamma_function
416 Chapter 52. <math.h> Mathematics
See Also
tgamma()
Synopsis
#include <math.h>
Description
Computes the gamma function10 of x, Γ(𝑥).
A domain or pole error might occur if x is non-positive.
A range error might occur if x is too large or too small.
Return Value
Returns the gamma function of x, Γ(𝑥).
Example
1 for (float i = 0.5; i <= 4; i += 0.5)
2 printf("%.1f: %f\n", i, tgamma(i));
Output:
0.5: 1.772454
1.0: 1.000000
1.5: 0.886227
2.0: 1.000000
2.5: 1.329340
3.0: 2.000000
3.5: 3.323351
4.0: 6.000000
See Also
lgamma()
Synopsis
#include <math.h>
Description
Returns the ceiling of the x: ⌈𝑥⌉.
This is the next whole number not smaller than x.
Beware this minor dragon: it’s not just “rounding up”. Well, it is for positive numbers, but negative
numbers effectively round toward zero. (Because the ceiling function is headed for the next largest whole
number and −4 is larger than −5.)
Return Value
Returns the next largest whole number larger than x.
Example
Notice for the negative numbers it heads toward zero, i.e. toward the next largest whole number—just like
the positives head toward the next largest whole number.
1 printf("%f\n", ceil(4.0)); // 4.000000
2 printf("%f\n", ceil(4.1)); // 5.000000
3 printf("%f\n", ceil(-2.0)); // -2.000000
4 printf("%f\n", ceil(-2.1)); // -2.000000
5 printf("%f\n", ceil(-3.1)); // -3.000000
See Also
floor(), round()
Synopsis
#include <math.h>
double floor(double x);
float floorf(float x);
long double floorl(long double x);
Description
Returns the floor of the value: ⌊𝑥⌋. This is the opposite of ceil().
This is the largest whole number that is not greater than x.
For positive numbers, this is like rounding down: 4.5 becomes 4.0.
418 Chapter 52. <math.h> Mathematics
For negative numbers, it’s like rounding up: -3.6 becomes -4.0.
In both cases, those results are the largest whole number not bigger than the given number.
Return Value
Returns the largest whole number not greater than x: ⌊𝑥⌋.
Example
Note how the negative numbers effectively round away from zero, unlike the positives.
1 printf("%f\n", floor(4.0)); // 4.000000
2 printf("%f\n", floor(4.1)); // 4.000000
3 printf("%f\n", floor(-2.0)); // -2.000000
4 printf("%f\n", floor(-2.1)); // -3.000000
5 printf("%f\n", floor(-3.1)); // -4.000000
See Also
ceil(), round()
Synopsis
#include <math.h>
Description
This function rounds x to the nearest integer in the current rounding direction.
The rounding direction can be set with fesetround() in <fenv.h>.
nearbyint() won’t raise the “inexact” floating point exception.
Return Value
Returns x rounded in the current rounding direction.
Example
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON // If supported
52.46. rint(), rintf(), rintl() 419
See Also
rint(), lrint(), round(), fesetround(), fegetround()
Synopsis
#include <math.h>
Description
This works just like nearbyint() except that is can raise the “inexact” floating point exception.
Return Value
Returns x rounded in the current rounding direction.
Example
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 fesetround(FE_TONEAREST);
10
14 fesetround(FE_TOWARDZERO);
420 Chapter 52. <math.h> Mathematics
15
See Also
nearbyint(), lrint(), round(), fesetround(), fegetround()
Synopsis
#include <math.h>
Description
Round a floating point number in the current rounding direction, but this time return an integer intead of
a float. You know, just to mix it up.
These come in two variants:
• lrint()—returns long int
• llrint()—returns long long int
If the result doesn’t fit in the return type, a domain or range error might occur.
Return Value
The value of x rounded to an integer in the current rounding direction.
Example
1 #include <stdio.h>
2 #include <math.h>
3 #include <fenv.h>
4
5 int main(void)
6 {
7 #pragma STDC FENV_ACCESS ON
8
9 fesetround(FE_TONEAREST);
10
11 printf("%ld\n", lrint(3.14)); // 3
52.48. round(), roundf(), roundl() 421
12 printf("%ld\n", lrint(3.74)); // 4
13
14 fesetround(FE_TOWARDZERO);
15
16 printf("%ld\n", lrint(1.99)); // 1
17 printf("%ld\n", lrint(-1.99)); // -1
18 }
See Also
nearbyint(), rint(), round(), fesetround(), fegetround()
Synopsis
#include <math.h>
Description
Rounds a number to the nearest whole value.
In case of halfsies, rounds away from zero (i.e. “round up” in magnitude).
The current rounding direction’s Jedi mind tricks don’t work on this function.
Return Value
The rounded value of x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", round(3.14)); // 3.000000
7 printf("%f\n", round(3.5)); // 4.000000
8
See Also
lround(), nearbyint(), rint(), lrint(), trunc()
422 Chapter 52. <math.h> Mathematics
Synopsis
#include <math.h>
Description
These are just like round() except they return integers.
Halfway values round away from zero, e.g. 1.5 rounds to 2 and −1.5 rounds to −2.
If the rounded value can’t fit in the return type, a domain or range error can occur.
Return Value
Returns the rounded value of x as an integer.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%ld\n", lround(3.14)); // 3
7 printf("%ld\n", lround(3.5)); // 4
8
9 printf("%ld\n", lround(-1.5)); // -2
10 printf("%ld\n", lround(-1.14)); // -1
11 }
See Also
round(), nearbyint(), rint(), lrint(), trunc()
52.50. trunc(), truncf(), truncl() 423
Synopsis
#include <math.h>
Description
These functions just drop the fractional part of a floating point number. Boom.
In other words, they always round toward zero.
Return Value
Returns the truncated floating point number.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", trunc(3.14)); // 3.000000
7 printf("%f\n", trunc(3.8)); // 3.000000
8
See Also
round(), lround(), nearbyint(), rint(), lrint()
Synopsis
#include <math.h>
Description
Returns the remainder of 𝑥𝑦 . The result will have the same sign as x.
Return Value
𝑥
Returns the remainder of 𝑦 with the same sign as x.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", fmod(-9.2, 5.1)); // -4.100000
7 printf("%f\n", fmod(9.2, 5.1)); // 4.100000
8 }
See Also
remainder()
Synopsis
#include <math.h>
Description
This is similar to fmod(), but not quite the same. fmod() is probably what you’re after if you’re expecting
remainders to wrap around like an odometer.
The C spec quotes IEC 60559 on how this works:
When 𝑦 ≠ 0, the remainder 𝑟 = 𝑥 REM 𝑦 is defined regardless of the rounding mode by
the mathematical relation 𝑟 = 𝑥 − 𝑛𝑦 , where 𝑛 is the integer nearest the exact value of 𝑥/𝑦;
whenever |𝑛 − 𝑥/𝑦| = 1/2, then 𝑛 is even. If 𝑟 = 0, its sign shall be that of 𝑥.
Hope that clears it up!
OK, maybe not. Here’s the upshot:
52.53. remquo(), remquof(), remquol() 425
You know how if you fmod() something by, say 2.0 you get a result that is somewhere between 0.0 and
2.0? And how if you just increase the number that you’re modding by 2.0, you can see the result climb
up to 2.0 and then wrap around to 0.0 like your car’s odometer?
remainder() works just like that, except if y is 2.0, it wraps from -1.0 to 1.0 instead of from 0.0 to
2.0.
In other words, the range of the function runs from -y/2 to y/2. Contrasted to fmod() that runs from
0.0 to y, remainder()’s output is just shifted down half a y.
And zero-remainder-anything is 0.
Except if y is zero, the function might return zero or a domain error might occur.
Return Value
The IEC 60559 result of x-remainder-y.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", remainder(3.7, 4)); // -0.300000
7 printf("%f\n", remainder(4.3, 4)); // 0.300000
8 }
See Also
fmod(), remquo()
Synopsis
#include <math.h>
Description
This is a funky little thing.
First of all, the return value is the remainder, the same as the remainder() function, so check that out.
And the quotient comes back in the quo pointer.
Or at least some of it does. You’ll get at least 3 bits worth of the quotient.
But why?
426 Chapter 52. <math.h> Mathematics
So a couple things.
One is that the quotient of some very large floating point numbers can easily be far too gigantic to fit in
even a long long unsigned int. So some of it might very well need to be lopped off, anyway.
But at 3 bits? How’s that even useful? That only gets you from 0 to 7!
The C99 Rationale document states:
The remquo functions are intended for implementing argument reductions which can exploit
a few low-order bits of the quotient. Note that 𝑥 may be so large in magnitude relative to 𝑦
that an exact representation of the quotient is not practical.
So… implementing argument reductions… which can exploit a few low-order bits… Ooookay.
CPPReference has this to say11 on the matter, which is spoken so well, I will quote wholesale:
This function is useful when implementing periodic functions with the period exactly repre-
sentable as a floating-point value: when calculating sin(𝜋𝑥) for a very large x, calling sin
directly may result in a large error, but if the function argument is first reduced with remquo,
the low-order bits of the quotient may be used to determine the sign and the octant of the
result within the period, while the remainder may be used to calculate the value with high
precision.
And there you have it. If you have another example that works for you… congratulations! :)
Return Value
Returns the same as remainder: The IEC 60559 result of x-remainder-y.
In addition, at least the lowest 3 bits of the quotient will be stored in quo with the same sign as x/y.
Example
There’s a great cos() example at CPPReference12 that covers a genuine use case.
But instead of stealing it, I’ll just post a simple example here and you can visit their site for a real one.
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 int quo;
7 double rem;
8
See Also
remainder(), imaxdiv()
Synopsis
#include <math.h>
Description
These functions return a number that has the magnitude of x and the sign of y. You can use them to coerce
the sign to that of another value.
Neither x nor y are modified, of course. The return value holds the result.
Return Value
Returns a value with the magnitude of x and the sign of y.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 double x = 34.9;
7 double y = -999.9;
8 double z = 123.4;
9
See Also
signbit()
Synopsis
#include <math.h>
Description
These functions return a quiet NaN13 . It is produced as if calling strtod() with "NAN" (or a variant
thereof) as an argument.
tagp points to a string which could be several things, including empty. The contents of the string deter-
mine which variant of NaN might get returned depending on the implementation.
Which version of NaN? Did you even know it was possible to get this far into the weeds with something
that wasn’t a number?
Case 1 in which you pass in an empty string, in which case these are the same:
nan("");
strtod("NAN()", NULL);
Case 2 in which the string contains only digits 0-9, letters a-z, letters A-Z, and/or underscore:
nan("goats");
strtod("NAN(goats)", NULL);
And Case 3, in which the string contains anything else and is ignored:
nan("!");
strtod("NAN", NULL);
As for what strtod() does with those values in parens, see the [strtod()] reference page. Spoiler: it’s
implementation-defined.
Return Value
Returns the requested quiet NaN, or 0 if such things aren’t supported by your system.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", nan("")); // nan
7 printf("%f\n", nan("goats")); // nan
8 printf("%f\n", nan("!")); // nan
9 }
See Also
strtod()
Synopsis
#include <math.h>
Description
As you probably know, floating point numbers can’t represent every possible real number. There are
limits.
And, as such, there exists a “next” and “previous” number after or before any floating point number.
These functions return the next (or previous) representable number. That is, no floating point numbers
exist between the given number and the next one.
The way it figures it out is it works from x in the direction of y, answering the question of “what is the
next representable number from x as we head toward y.
Return Value
Returns the next representable floating point value from x in the direction of y.
If x equals y, returns y. And also x, I suppose.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%.*f\n", DBL_DECIMAL_DIG, nextafter(0.5, 1.0));
7 printf("%.*f\n", DBL_DECIMAL_DIG, nextafter(0.349, 0.0));
8 }
Output on my system:
0.50000000000000011
0.34899999999999992
See Also
nexttoward()
Synopsis
include <math.h>
Description
These functions are the same as nextafter() except the second parameter is always long double.
Return Value
Returns the same as nextafter() except if x equals y, returns y cast to the function’s return type.
Example
1 #include <stdio.h>
2 #include <float.h>
3 #include <math.h>
4
5 int main(void)
6 {
7 printf("%.*f\n", DBL_DECIMAL_DIG, nexttoward(0.5, 1.0));
8 printf("%.*f\n", DBL_DECIMAL_DIG, nexttoward(0.349, 0.0));
9 }
Output on my system:
0.50000000000000011
0.34899999999999992
See Also
nextafter()
Synopsis
#include <math.h>
Description
The positive difference between x and y is the difference… except if the difference is less than 0, it’s
clamped to 0.
These functions might throw a range error.
52.59. fmax(), fmaxf(), fmaxl(), fmin(), fminf(), fminl() 431
Return Value
Returns the difference of x-y if the difference is greater than 0. Otherwise it returns 0.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", fdim(10.0, 3.0)); // 7.000000
7 printf("%f\n", fdim(3.0, 10.0)); // 0.000000, clamped
8 }
Synopsis
#include <math.h>
Description
Straightforwardly, these functions return the minimum or maximum of two given numbers.
If one of the numbers is NaN, the functions return the non-NaN number. If both arguments are NaN, the
functions return NaN.
Return Value
Returns the minimum or maximum values, with NaN handled as mentioned above.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%f\n", fmin(10.0, 3.0)); // 3.000000
432 Chapter 52. <math.h> Mathematics
Synopsis
#include <math.h>
Description
This performs the operation (𝑥 × 𝑦) + 𝑧 , but does so in a nifty way. It does the computation as if it had
infinite precision, and then rounds the final result to the final data type according to the current rounding
mode.
Contrast to if you’d do the math yourself, where it would have rounded each step of the way, potentially.
Also some architectures have a CPU instruction to do exactly this calculation, so it can do it super quick.
(If it doesn’t, it’s considerably slower.)
You can tell if your CPU supports the fast version by checking that the macro FP_FAST_FMA is set to 1.
(The float and long variants of fma() can be tested with FP_FAST_FMAF and FP_FAST_FMAL, respec-
tively.)
These functions might cause a range error to occur.
Return Value
Returns (x * y) + z.
Example
1 printf("%f\n", fma(1.0, 2.0, 3.0)); // 5.000000
Synopsis
#include <math.h>
Description
These macros compare floating point numbers. Being macros, we can pass in any floating point type.
You might think you can already do that with just regular comparison operators—and you’d be right!
One one exception: the comparison operators raise the “invalid” floating exception if one or more of the
operands is NaN. These macros do not.
Note that you must only pass floating point types into these functions. Passing an integer or any other
type is undefined behavior.
Return Value
isgreater() returns the result of x > y.
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%d\n", isgreater(10.0, 3.0)); // 1
7 printf("%d\n", isgreaterequal(10.0, 10.0)); // 1
8 printf("%d\n", isless(10.0, 3.0)); // 0
9 printf("%d\n", islessequal(10.0, 3.0)); // 0
10 }
See Also
islessgreater(), isunordered()
52.62 islessgreater()
Test if a floating point number is less than or greater than another.
Synopsis
#include <math.h>
Description
This macro is similar to isgreater() and all those, except it made the section name too long if I included
it up there. So it gets its own spot.
This returns true if 𝑥 < 𝑦 or 𝑥 > 𝑦 .
Even though it’s a macro, we can rest assured that x and y are only evaluated once.
And even if x or y are NaN, this will not throw an “invalid” exception, unlike the normal comparison
operators.
If you pass in a non-floating type, the behavior is undefined.
Return Value
Returns (x < y) || (x > y).
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%d\n", islessgreater(10.0, 3.0)); // 1
7 printf("%d\n", islessgreater(10.0, 30.0)); // 1
8 printf("%d\n", islessgreater(10.0, 10.0)); // 0
9 }
See Also
isgreater(), isgreaterequal(), isless(), islessequal(), isunordered()
52.63 isunordered()
Macro returns true if either floating point argument is NaN.
Synopsis
#include <math.h>
Description
The spec writes:
The isunordered macro determines whether its arguments are unordered.
See? Told you C was easy!
It does also elaborate that the arguments are unordered if one or both of them are NaN.
Return Value
This macro returns true if one or both of the arguments are NaN.
52.63. isunordered() 435
Example
1 #include <stdio.h>
2 #include <math.h>
3
4 int main(void)
5 {
6 printf("%d\n", isunordered(1.0, 2.0)); // 0
7 printf("%d\n", isunordered(1.0, sqrt(-1))); // 1
8 printf("%d\n", isunordered(NAN, 30.0)); // 1
9 printf("%d\n", isunordered(NAN, NAN)); // 1
10 }
See Also
isgreater(), isgreaterequal(), isless(), islessequal(), islessgreater()
436 Chapter 52. <math.h> Mathematics
Chapter 53
These functions enable you to rewind the call stack to an earlier point, with a bunch of gotchas. See the
chapter on setjmp()/longjmp() for more info.
Function Description
longjmp() Return to the previously-placed bookmark
setjmp() Bookmark this place to return to later
There’s also a new opaque type, jmp_buf, that holds all the information needed to pull off this magic
trick.
If you want your automatic local variables to be correct after a call to longjmp(). declare them as
volatile where you called setjmp().
53.1 setjmp()
Save this location as one to return to later
Synopsis
#include <setjmp.h>
Description
This is how you save your position so you can longjmp() back it, later. Think of it as setting up a warp
destination for later use.
Basically, you call this, giving it an env it can fill in with all the information it needs to come back here
later. This env is one you’ll pass to longjmp() later when you want to teleport back here.
And the really funky part is this can return two different ways:
1. It can return 0 from the call where you set up the jump destination.
2. If can return non-zero when you actually warp back here as the result of a call to longjmp().
What you can do is check the return value to see which case has occurred.
You’re only allowed to call setjmp() in a limited number of circumstances.
437
438 Chapter 53. <setjmp.h> Non-local Goto
1. As a standalone expression:
setjmp(env);
You can also cast it to (void) if you really wanted to do such a thing.
2. As the complete controlling expression in an if or switch.
if (setjmp(env)) { ... }
But not this as it’s not the complete controlling expression in this case:
if (x == 2 && setjmp()) { ... } // Undefined behavior
Return Value
This one is funky. It returns one of two things:
Returns 0 if this was the call to setjmp() to set it up.
Returns non-zero if being here was the result of a call to longjmp(). (Namely, it returns the value passed
into the longjmp() function.)
Example
Here’s a function that calls setjmp() to set things up (where it returns 0), then calls a couple levels
deep into functions, and finally short-circuits the return path by longjmp()ing back to the place where
setjmp() was called, earlier. This time, it passes 3490 as a value, which setjmp() returns.
1 #include <stdio.h>
2 #include <setjmp.h>
3
4 jmp_buf env;
5
6 void depth2(void)
7 {
8 printf("Entering depth 2\n");
9 longjmp(env, 3490); // Jump back to setjmp()!!
10 printf("Leaving depth 2\n"); // This won't happen
11 }
12
13 void depth1(void)
14 {
15 printf("Entering depth 1\n");
16 depth2();
17 printf("Leaving depth 1\n"); // This won't happen
18 }
19
20 int main(void)
53.2. longjmp() 439
21 {
22 switch (setjmp(env)) {
23 case 0:
24 printf("Calling into functions, setjmp() returned 0\n");
25 depth1();
26 printf("Returned from functions\n"); // This won't happen
27 break;
28
29 case 3490:
30 printf("Bailed back to main, setjmp() returned 3490\n");
31 break;
32 }
33 }
Notice that the second printf() in case 0 didn’t run; it got jumped over by longjmp()!
See Also
longjmp()
53.2 longjmp()
Return to the previous setjmp() location
Synopsis
#include <setjmp.h>
Description
This returns to a previous call to setjmp() back in the call history. setjmp() will return the val passed
into longjmp().
The env passed to setjmp() should be the same one you pass into longjmp().
There are a bunch of potential issues with doing this, so you’ll want to be careful that you avoid undefined
behavior by not doing the following:
1. Don’t call longjmp() if the corresponding setjmp() was in a different thread.
2. Don’t call longjmp() if you didn’t call setjmp() first.
3. Don’t call longjmp() if the function that called setjmp() has completed.
4. Don’t call longjmp() if the call to setjmp() had a variable length array (VLA) in scope and the
scope has ended.
5. Don’t call longjmp() if there are any VLAs in any active scopes between the setjmp() and the
longjmp(). A good rule of thumb here is to not mix VLAs and longjmp().
440 Chapter 53. <setjmp.h> Non-local Goto
Though longjmp() attempts to restore the machine to the state at the setjmp(), including local variables,
there are some things that aren’t brought back to life:
• Non-volatile local variables that might have changed
• Floating point status flags
• Open files
• Any other component of the abstract machine
Return Value
This one is also funky in that it is one of the few functions in C that never returns!
Example
Here’s a function that calls setjmp() to set things up (where it returns 0), then calls a couple levels
deep into functions, and finally short-circuits the return path by longjmp()ing back to the place where
setjmp() was called, earlier. This time, it passes 3490 as a value, which setjmp() returns.
1 #include <stdio.h>
2 #include <setjmp.h>
3
4 jmp_buf env;
5
6 void depth2(void)
7 {
8 printf("Entering depth 2\n");
9 longjmp(env, 3490); // Jump back to setjmp()!!
10 printf("Leaving depth 2\n"); // This won't happen
11 }
12
13 void depth1(void)
14 {
15 printf("Entering depth 1\n");
16 depth2();
17 printf("Leaving depth 1\n"); // This won't happen
18 }
19
20 int main(void)
21 {
22 switch (setjmp(env)) {
23 case 0:
24 printf("Calling into functions, setjmp() returned 0\n");
25 depth1();
26 printf("Returned from functions\n"); // This won't happen
27 break;
28
29 case 3490:
30 printf("Bailed back to main, setjmp() returned 3490\n");
31 break;
32 }
33 }
Notice that the second printf() in case 0 didn’t run; it got jumped over by longjmp()!
53.2. longjmp() 441
See Also
setjmp()
442 Chapter 53. <setjmp.h> Non-local Goto
Chapter 54
Function Description
signal() Set a signal handler for a given signal
raise() Cause a signal to be raised
54.1 signal()
Set a signal handler for a given signal
Synopsis
#include <signal.h>
Description
How’s that for a function declaration?
Let’s ignore it for a moment and just talk about what this function does.
When a signal is raised, something is going to happen. This function lets you decide to do one of these
things when the signal is raised:
• Ignore the signal
• Perform the default action
• Have a specific function called
1
https://man.archlinux.org/man/sigaction.2.en
443
444 Chapter 54. <signal.h> signal handling
The signal() function takes two arguments. The first, sig, is the name of the signal to handle.
Signal Description
SIGABRT Raised when abort() is called
SIGFPE Floating-point arithmetic exception
SIGILL CPU tried to execute an illegal instruction
SIGINT Interrupt signal, as if CTRL-C were pressed
SIGSEGV Segmention Violation: attempted to access restricted memory
SIGTERM Termination request2
So that’s the first bit when you call signal()—tell it the signal in question:
signal(SIGINT, ...
func Description
SIG_DFL Perform the default action on this signal
SIG_IGN Ignore this signal
For example:
signal(SIGTERM, SIG_DFL); // Default action on SIGTERM
signal(SIGINT, SIG_IGN); // Ignore SIGINT
But what if you want to have your own handler do something instead of the default or ignoring it? You
can pass in your own function to be called. That’s what the crazy function signature is partially about. It’s
saying that the argument can be a pointer to a function that takes an int argument and returns void.
So if you wanted to call your handler, you could have code like this:
int handler(int sig)
{
// Handle the signal
}
int main(void)
{
signal(SIGINT, handler);
• signal() with a first argument equivalent to the argument that was passed into the handler
In addition, if the signal was not due to abort() or raise(), the handler can’t access any object with
static or thread-storage duration unless it’s lock-free.
An exception is that you can assign to (but not read from!) a variable of type volatile sig_atomic_t.
It’s up to the implementation, but the signal handler might be reset to SIG_DFL just before the handler is
called.
It’s undefined behavior to call signal() in a multithreaded program.
It’s undefined behavior to return from the handler for SIGFPE, SIGILL, SIGSEGV, or any implementation-
defined value. You must exit.
The implementation might or might not prevent other signals from arising while in the signal handler.
Return Value
On success, signal() returns a pointer to the previous signal handler set by a call to signal() for that
particular signal number. If you haven’t called it set, returns SIG_DFL.
On failure, SIG_ERR is returned and errno is set to a positive value.
Example
Here’s a program that causes SIGINT to be ignored. Commonly you trigger this signal by hitting CTRL-C.
1 #include <stdio.h>
2 #include <signal.h>
3
4 int main(void)
5 {
6 signal(SIGINT, SIG_IGN);
7
Output:
You can't hit CTRL-C to exit this program. Try it!
This program sets the signal handler, then raises the signal. The signal handler fires.
1 #include <stdio.h>
2 #include <signal.h>
3
14 signal(sig, handler);
15 }
446 Chapter 54. <signal.h> signal handling
16
17 int main(void)
18 {
19 signal(SIGINT, handler);
20
21 raise(SIGINT);
22 raise(SIGINT);
23 raise(SIGINT);
24 }
Output:
Got signal 2!
Got signal 2!
Got signal 2!
This example catches SIGINT but then sets a flag to 1. Then the main loop sees the flag and exits.
1 #include <stdio.h>
2 #include <signal.h>
3
4 volatile sig_atomic_t x;
5
11 int main(void)
12 {
13 signal(SIGINT, handler);
14
See Also
raise(), abort()
54.2 raise()
Cause a signal to be raised
Synopsis
#include <signal.h>
Description
Causes the signal handler for the signal sig to be called. If the handler is SIG_DFL or SIG_IGN, then the
default action or no action happens.
raise() returns after the signal handler has finished running.
54.2. raise() 447
Interestingly, if you cause a signal to happen with raise(), you can call library functions from within
the signal handler without causing undefined behavior. I’m not sure how this fact is practically useful,
though.
Return Value
Returns 0 on success. Nonzero otherwise.
Example
This program sets the signal handler, then raises the signal. The signal handler fires.
1 #include <stdio.h>
2 #include <signal.h>
3
14 signal(sig, handler);
15 }
16
17 int main(void)
18 {
19 signal(SIGINT, handler);
20
21 raise(SIGINT);
22 raise(SIGINT);
23 raise(SIGINT);
24 }
Output:
Got signal 2!
Got signal 2!
Got signal 2!
See Also
signal()
448 Chapter 54. <signal.h> signal handling
Chapter 55
If you’re coding up something low-level like a memory allocator that interfaces with your OS, you might
need this header file. But most C devs go their careers without using it.
Alignment1 is all about multiples of addresses on which objects can be stored. Can you store this at any
address? Or must it be a starting address that’s divisible by 2? Or 8? Or 16?
Name Description
alignas() Specify alignment, expands to _Alignas
alignof() Get alignment, expands to _Alignof
Quick note: alignments greater than that of max_align_t are known as overalignments and are
implementation-defined.
Synopsis
#include <stdalign.h>
alignas(type-name)
alignas(constant-expression)
_Alignas(type-name)
_Alignas(constant-expression)
Description
Use this alignment specifier to force the alignment of particular variables. For instance, we can declare c
to be char, but aligned as if it were an int:
char alignas(int) c;
1
https://en.wikipedia.org/wiki/Data_structure_alignment
449
450 Chapter 55. <stdalign.h> Macros for Alignment
You can put a constant integer expression in there, as well. The compiler will probably impose limits on
what these values can be. Small powers of 2 (1, 2, 4, 8, and 16) are generally safe bets.
char alignas(8) c; // align on 8-byte boundaries
For convenience, you can also specify 0 if you want the default alignment (as if you hadn’t said alignas()
at all):
char alignas(0) c; // use default alignment for this type
Example
1 #include <stdalign.h>
2 #include <stdio.h> // for printf()
3 #include <stddef.h> // for max_align_t
4
5 int main(void)
6 {
7 int i, j;
8 char alignas(max_align_t) a, b;
9 char alignas(int) c, d;
10 char e, f;
11
Output on my system follows. Notice the difference between the pairs of values.
See Also
alignof, max_align_t
55.2. alignof() _Alignof() 451
Synopsis
#include <stdalign.h>
alignof(type-name)
_Alignof(type-name)
Description
This evaluates to a value of type size_t that gives the alignment of a particular type on your system.
Return Value
Returns the alignment value, i.e. the address of the beginning of the given type of object must begin on
an address boundary divisible by this number.
Example
Print out the alignments of a variety of different types.
1 #include <stdalign.h>
2 #include <stdio.h> // for printf()
3 #include <stddef.h> // for max_align_t
4
5 struct t {
6 int a;
7 char b;
8 float c;
9 };
10
11 int main(void)
12 {
13 printf("char : %zu\n", alignof(char));
14 printf("short : %zu\n", alignof(short));
15 printf("int : %zu\n", alignof(int));
16 printf("long : %zu\n", alignof(long));
17 printf("long long : %zu\n", alignof(long long));
18 printf("double : %zu\n", alignof(double));
19 printf("long double: %zu\n", alignof(long double));
20 printf("struct t : %zu\n", alignof(struct t));
21 printf("max_align_t: %zu\n", alignof(max_align_t));
22 }
Output on my system:
char : 1
short : 2
int : 4
long : 8
long long : 8
double : 8
long double: 16
struct t : 16
max_align_t: 16
452 Chapter 55. <stdalign.h> Macros for Alignment
See Also
alignas, max_align_t
Chapter 56
Macro Description
va_arg() Get the next variable argument
va_copy() Copy a va_list and the work done so far
va_end() Signify we’re done processing variable arguments
va_start() Initialize a va_list to start variable argument processing
This header file is what allows you to write functions that take a variable number of arguments.
In addition to the macros, you get a new type that helps C keep track of where it is in the variable-number-
of-arguments-processing: va_list. This type is opaque, and you’ll be passing it around to the various
macros to help get at the arguments.
Note that every variadic function requires at least one non-variable parameter. You need this to kick off
processing with va_start().
56.1 va_arg()
Get the next variable argument
Synopsis
#include <stdarg.h>
Description
If you have a variable argument list you’ve initialized with va_start(), pass it to this one along with the
type of argument you’re trying to get, e.g.
int x = va_arg(args, int);
float y = va_arg(args, float);
Return Value
Evaluates to the value and type of the next variable argument.
453
454 Chapter 56. <stdarg.h> Variable Arguments
Example
Here’s a demo that adds together an arbitrary number of integers. The first argument is the number of
integers to add together. We’ll make use of that to figure out how many times we have to call va_arg().
1 #include <stdio.h>
2 #include <stdarg.h>
3
14 total += n;
15 }
16
19 return total;
20 }
21
22 int main(void)
23 {
24 printf("%d\n", add(4, 6, 2, -4, 17)); // 6 + 2 - 4 + 17 = 21
25 printf("%d\n", add(2, 22, 44)); // 22 + 44 = 66
26 }
See Also
va_start(), va_end()
56.2 va_copy()
Copy a va_list and the work done so far
Synopsis
#include <stdarg.h>
Description
The main intended use of this is to save your state partway through processing variable arguments so you
can scan ahead and then rewind back to the save point.
You pass in a src va_list and it copies it to dest.
If you’ve already called this once for a particular dest, you can’t call it (or va_start()) again with the
same dest unless you call va_end() on that dest first.
56.2. va_copy() 455
va_copy(dest, src);
va_copy(dest, src2); // BAD!
va_copy(dest, src);
va_start(dest, var); // BAD!
va_copy(dest, src);
va_end(dest);
va_copy(dest, src2); // OK!
va_copy(dest, src);
va_end(dest);
va_start(dest, var); // OK!
Return Value
Returns nothing.
Example
Here’s an example where we’re adding together all the variable arguments, but then we want to go back
and add on all the numbers past the first two, for example if the arguments are:
10 20 30 40
First we add them all for 100, and then we add on everything from the third number on, so add on 30+40
for a total of 170.
We’ll do this by saving our place in the variable argument processing with va_copy and then using that
later to reprocess the trailing arguments.
(And yes, I know there’s a mathematical way to do this without all the rewinding, but I’m having an heck
of a time coming up with a good example!)
1 #include <stdio.h>
2 #include <stdarg.h>
3
4 // Add all the numbers together, but then add on all the numbers
5 // past the second one again.
6 int contrived_adder(int count, ...)
7 {
8 if (count < 3) return 0; // OK, I'm being lazy. You got me.
9
10 int total = 0;
11
14 va_start(args, count);
15
21 if (i == 2)
22 va_copy(mid_args, args);
23
29 // But now let's start with mid_args and add all those on:
30 for (int i = 0; i < count - 2; i++)
31 total += va_arg(mid_args, int);
32
35 return total;
36 }
37
38 int main(void)
39 {
40 // 10+20+30 + 30 == 90
41 printf("%d\n", contrived_adder(3, 10, 20, 30));
42
See Also
va_start(), va_arg(), va_end()
56.3 va_end()
Signify we’re done processing variable arguments
Synopsis
#include <stdarg.h>
Description
After you’ve va_start()ed or va_copy’d a new va_list, you must call va_end() with it before it
goes out of scope.
You also have to do this if you’re going to call va_start() or va_copy() again on a variable you’ve
already done that to.
Them’s the rules if you want to avoid undefined behavior.
But just think of it as cleanup. You called va_start(), so you’ll call va_end() when you’re done.
Return Value
Returns nothing.
Example
Here’s a demo that adds together an arbitrary number of integers. The first argument is the number of
integers to add together. We’ll make use of that to figure out how many times we have to call va_arg().
56.4. va_start() 457
1 #include <stdio.h>
2 #include <stdarg.h>
3
14 total += n;
15 }
16
19 return total;
20 }
21
22 int main(void)
23 {
24 printf("%d\n", add(4, 6, 2, -4, 17)); // 6 + 2 - 4 + 17 = 21
25 printf("%d\n", add(2, 22, 44)); // 22 + 44 = 66
26 }
See Also
va_start(), va_copy()
56.4 va_start()
Initialize a va_list to start variable argument processing
Synopsis
#include <stdarg.h>
Description
You’ve declared a variable of type va_list to keep track of the variable argument processing… now how
to initialize it so you can start calling va_arg() to get those arguments?
va_start() to the rescue!
What you do is pass in your va_list, here shown as parameter ap. Just pass the list, not a pointer to it.
Then for the second argument to va_start(), you give the name of the parameter that you want to start
processing arguments after. This must be the parameter right before the ... in the argument list.
If you’ve already called va_start() on a particular va_list and you want to call va_start() on it
again, you must call va_end() first!
458 Chapter 56. <stdarg.h> Variable Arguments
Return Value
Returns nothing!
Example
Here’s a demo that adds together an arbitrary number of integers. The first argument is the number of
integers to add together. We’ll make use of that to figure out how many times we have to call va_arg().
1 #include <stdio.h>
2 #include <stdarg.h>
3
14 total += n;
15 }
16
19 return total;
20 }
21
22 int main(void)
23 {
24 printf("%d\n", add(4, 6, 2, -4, 17)); // 6 + 2 - 4 + 17 = 21
25 printf("%d\n", add(2, 22, 44)); // 22 + 44 = 66
26 }
See Also
va_arg(), va_end()
Chapter 57
<stdatomic.h> Atomic-Related
Functions
Function Description
atomic_compare_exchange_strong_explicit() Atomic compare and exchange, strong, explicit
atomic_compare_exchange_strong() Atomic compare and exchange, strong
atomic_compare_exchange_weak_explicit() Atomic compare and exchange, weak, explicit
atomic_compare_exchange_weak() Atomic compare and exchange, weak
atomic_exchange_explicit() Replace a value in an atomic object, explicit
atomic_exchange() Replace a value in an atomic object
atomic_fetch_add_explicit() Atomically add to an atomic integer, explicit
atomic_fetch_add() Atomically add to an atomic integer
atomic_fetch_and_explicit() Atomically bitwise-AND an atomic integer,
explicit
atomic_fetch_and() Atomically bitwise-AND an atomic integer
atomic_fetch_or_explicit() Atomically bitwise-OR an atomic integer, explicit
atomic_fetch_or() Atomically bitwise-OR an atomic integer
atomic_fetch_sub_explicit() Atomically subtract from an atomic integer,
explicit
atomic_fetch_sub() Atomically subtract from an atomic integer
atomic_fetch_xor_explicit() Atomically bitwise-XOR an atomic integer,
explicit
atomic_fetch_xor() Atomically bitwise-XOR an atomic integer
atomic_flag_clear_explicit() Clear an atomic flag, explicit
atomic_flag_clear() Clear an atomic flag
atomic_flag_test_and_set_explicit() Test and set an atomic flag, explicit
atomic_flag_test_and_set() Test and set an atomic flag
atomic_init() Initialize an atomic variable
atomic_is_lock_free() Determine if an atomic type is lock free
atomic_load_explicit() Return a value from an atomic variable, explicit
atomic_load() Return a value from an atomic variable
atomic_signal_fence() Fence for intra-thread signal handlers
atomic_store_explicit() Store a value in an atomic variable, explicit
atomic_store() Store a value in an atomic variable
atomic_thread_fence() Set up a fence
ATOMIC_VAR_INIT() Create an initializer for an atomic variable
kill_dependency() End a dependency chain
You might need to add -latomic to your compilation command line on Unix-like operating systems.
459
460 Chapter 57. <stdatomic.h> Atomic-Related Functions
You can make your own additional types with the _Atomic type qualifier:
_Atomic double x;
Value Meaning
0 Never lock-free.
1 Sometimes lock-free1 .
2 Always lock-free.
memory_order Description
memory_order_seq_cst Sequential Consistency
memory_order_acq_rel Acquire/Release
memory_order_release Release
memory_order_acquire Acquire
memory_order_consume Consume
memory_order_relaxed Relaxed
You can feed these into atomic functions with the _explicit suffix.
The non-_explcit versions of the functions are the same as if you’d called the _explicit counterpart
with memory_order_seq_cst.
57.5 ATOMIC_VAR_INIT()
Create an initializer for an atomic variable
1
Maybe it depends on the run-time environment and can’t be known at compile-time.
462 Chapter 57. <stdatomic.h> Atomic-Related Functions
Synopsis
#include <stdatomic.h>
Description
This macro expands to an initializer, so you can use it when a variable is defined.
The type of the value should be the base type of the atomic variable.
The initialization itself is not an atomic operation, ironically.
CPPReference says this is deprecated2 and likely to be removed. Standards document p1138r03 elaborates
that the macro is limited in that it can’t properly initialize atomic structs, and its original raison d’être
turned out to not be useful.
Just initialize the variable straight-up, instead.
Return Value
Expands to an initializer suitable for this atomic variable.
Example
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x = ATOMIC_VAR_INIT(3490); // Deprecated
7 printf("%d\n", x);
8 }
See Also
atomic_init()
57.6 atomic_init()
Initialize an atomic variable
Synopsis
#include <stdatomic.h>
Description
You can use this to initialize an atomic variable.
The type of the value should be the base type of the atomic variable.
2
https://en.cppreference.com/w/cpp/atomic/ATOMIC_VAR_INIT
3
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1138r0.pdf
57.7. kill_dependency() 463
Return Value
Returns nothing!
Example
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x;
7
8 atomic_init(&x, 3490);
9
10 printf("%d\n", x);
11 }
See Also
ATOMIC_VAR_INIT(), atomic_store(), atomic_store_explicit()
57.7 kill_dependency()
End a dependency chain
Synopsis
#include <stdatomic.h>
Description
This is potentially useful for optimizing if you’re using memory_order_consume anywhere.
And if you know what you’re doing. If unsure, learn more before trying to use this.
Return Value
Returns the value passed in.
Example
In this example, i carries a dependency into x. And would do into y, except for the call to
kill_dependency().
1 #include <stdio.h>
2 #include <stdatomic.h>
3
464 Chapter 57. <stdatomic.h> Atomic-Related Functions
4 int main(void)
5 {
6 atomic_int a;
7 int i = 10, x, y;
8
11 i = atomic_load_explicit(&a, memory_order_consume);
12 x = i;
13 y = kill_dependency(i);
14
57.8 atomic_thread_fence()
Set up a fence
Synopsis
#include <stdatomic.h>
Description
This sets up a memory fence with the specified order.
order Description
memory_order_seq_cst Sequentially consistency acquire/release fence
memory_order_acq_rel Acquire/release dence
memory_order_release Release fence
memory_order_acquire Acquire fence
memory_order_consume Acquire fence (again)
memory_order_relaxed No fence at all—no point in calling with this
You might try to avoid using these and just stick with the different modes with atomic_store_explicit()
and atomic_load_explicit(). Or not.
Return Value
Returns nothing!
Example
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
5 atomic_int shared_1 = 1;
6 atomic_int shared_2 = 2;
7
9 {
10 (void)arg;
11
14 atomic_thread_fence(memory_order_release);
15
18 return 0;
19 }
20
29 atomic_thread_fence(memory_order_acquire);
30
31 if (shared_2 == 20) {
32 printf("Shared_1 better be 10 and it's %d\n", shared_1);
33 } else {
34 printf("Anything's possible: %d %d\n", shared_1, shared_2);
35 }
36
37 return 0;
38 }
39
40 int main(void)
41 {
42 thrd_t t1, t2;
43
47 thrd_join(t1, NULL);
48 thrd_join(t2, NULL);
49 }
See Also
atomic_store_explicit(), atomic_load_explicit(), atomic_signal_fence()
57.9 atomic_signal_fence()
Fence for intra-thread signal handlers
Synopsis
#include <stdatomic.h>
Description
This works like atomic_thread_fence() except its purpose is within in a single thread; notably for use
in a signal handler in that thread.
Since signals can happen at any time, we might need a way to be certain that any writes by the thread that
happened before the signal handler be visible within that signal handler.
Return Value
Returns nothing!
Example
Partial demo. (Note that it’s technically undefined behavior to call printf() in a signal handler.)
1 #include <stdio.h>
2 #include <signal.h>
3 #include <stdatomic.h>
4
5 int global;
6
16 atomic_signal_fence(memory_order_acquire);
17
18 printf("%d\n", global);
19 }
20
21 int main(void)
22 {
23 signal(SIGINT, handler);
24
25 global = 10;
26
27 atomic_signal_fence(memory_order_release);
28
See Also
atomic_thread_fence(), signal()
57.10 atomic_is_lock_free()
Determine if an atomic type is lock free
57.10. atomic_is_lock_free() 467
Synopsis
#include <stdatomic.h>
Description
Determines if the variable obj of type A is lock-free. Can be used with any type.
Unlike the lock-free macros which can be used at compile-time, this is strictly a run-time function. So
in places where the macros say “maybe”, this function will definitely tell you one way or another if the
atomic variable is lock-free.
This is useful when you’re defining your own atomic variables and want to know their lock-free status.
Return Value
True if the variable is lock-free, false otherwise.
Example
Test if a couple structs and an atomic double are lock-free. On my system, the larger struct is too
big to be lock-free, but the other two are OK.
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 struct foo {
7 int x, y;
8 };
9
10 struct bar {
11 int x, y, z;
12 };
13
14 _Atomic(double) a;
15 struct foo b;
16 struct bar c;
17
See Also
Lock-free Macros
468 Chapter 57. <stdatomic.h> Atomic-Related Functions
57.11 atomic_store()
Store a value in an atomic variable
Synopsis
#include <stdatomic.h>
Description
Store a value in an atomic variable, possible synchronized.
This is like a plain assignment, but with more flexibility.
These have the same storage effect for an atomic_int x:
x = 10;
atomic_store(&x, 10);
atomic_store_explicit(&x, 10, memory_order_seq_cst);
But the last function, atomic_store_explicit(), lets you specify the memory order.
Since this is a “release-y” operation, none of the “acquire-y” memory orders are legal. order can be only
be memory_order_seq_cst, memory_order_release, or memory_order_relaxed.
order cannot be memory_order_acq_rel, memory_order_acquire, or memory_order_consume.
Return Value
Returns nothing!
Example
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x = 0;
7 atomic_int y = 0;
8
9 atomic_store(&x, 10);
10
See Also
atomic_init(), atomic_load(), atomic_load_explicit(), atomic_exchange(),
atomic_exchange_explicit(), atomic_compare_exchange_strong(),
atomic_compare_exchange_strong_explicit(), atomic_compare_exchange_weak(),
atomic_compare_exchange_weak_explicit(), atomic_fetch_*()
57.12. atomic_load() 469
57.12 atomic_load()
Return a value from an atomic variable
Synopsis
#include <stdatomic.h>
Description
For a pointer to an object of type A, atomically returns its value C. This is a generic function that can be
used with any type.
Since this is an “acquire-y” operation, none of the “release-y” memory orders are legal. order
can be only be memory_order_seq_cst, memory_order_acquire, memory_order_consume, or
memory_order_relaxed.
Return Value
Returns the value stored in object.
Example
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x = 10;
7
8 int v = atomic_load(&x);
9
10 printf("%d\n", v); // 10
11 }
See Also
atomic_store(), atomic_store_explicit()
57.13 atomic_exchange()
Replace a value in an atomic object
470 Chapter 57. <stdatomic.h> Atomic-Related Functions
Synopsis
#include <stdatomic.h>
Description
Sets the value in object to desired.
object is type A, some atomic type.
This is very similar to atomic_store(), except the previous value is atomically returned.
Return Value
Returns the previous value of object.
Example
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x = 10;
7
Output:
x is 20
x was 10
See Also
atomic_init(), atomic_load(), atomic_load_explicit(), atomic_store(),
atomic_store_explicit() atomic_compare_exchange_strong(),
atomic_compare_exchange_strong_explicit(), atomic_compare_exchange_weak(),
atomic_compare_exchange_weak_explicit()
57.14 atomic_compare_exchange_*()
Atomic compare and exchange
Synopsis
57.14. atomic_compare_exchange_*() 471
#include <stdatomic.h>
Description
The venerable basis for some many things lock-free: compare and exchange.
In the above prototypes, A is the type of the atomic object, and C is the equivalent base type.
Ignoring the _explicit versions for a moment, what these do is:
• If the value pointed to by object is equal to the value pointed to by expected, then the value
pointed to by object is set to desired. And the function returns true indicating the exchange did
take place.
• Else the value pointed to by expected (yes, expected) is set to desired and the function returns
false indicating the exchange did not take place.
*expected = desired
return false
}
The _weak variants might spontaneously fail, so even if *object == *desired, it might not change the
value and will return false. So you’ll want that in a loop if you use it5 .
The _explicit variants have two memory orders: success if *object is set to desired, and failure
if it is not.
These are test-and-set functions, so you can use memory_order_acq_rel with the _explicit variants.
Return Value
Returns true if *object was *expected. Otherwise, false.
4
This effectively does the same thing, but it’s clearly not atomic.
5
The spec says, “This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g. load-
locked store-conditional machines.” And adds, “When a compare-and-exchange is in a loop, the weak version will yield better
performance on some platforms. When a weak compare-and-exchange would require a loop and a strong one would not, the strong
one is preferable.”
472 Chapter 57. <stdatomic.h> Atomic-Related Functions
Example
A contrived example where multiple threads add 2 to a shared value in a lock-free way.
(It would be better to use += 2 to get this done in real life unless you were using some _explicit
wizardry.)
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
7 atomic_int value;
8
18 do {
19 next = cur + 2;
20 } while (!atomic_compare_exchange_strong(&value, &cur, next));
21 }
22
23 return 0;
24 }
25
26 int main(void)
27 {
28 thrd_t t1, t2;
29
33 thrd_join(t1, NULL);
34 thrd_join(t2, NULL);
35
See Also
atomic_load(), atomic_load_explicit(), atomic_store(), atomic_store_explicit(),
atomic_exchange(), atomic_exchange_explicit(), atomic_fetch_*()
57.15 atomic_fetch_*()
Atomically modify atomic variables
57.15. atomic_fetch_*() 473
Synopsis
#include <stdatomic.h>
Description
These are actually a group of 10 functions. You substitute one of the following for KEY to perform that
operation:
• add
• sub
• or
• xor
• and
So these functions can add or subtract values to or from an atomic variable, or can perform bitwise-OR,
XOR, or AND on them.
Use it with integer or pointer types. Though the spec is a little vague on the matter, other types make C
unhappy. It goes out of its way to avoid undefined behavior with signed integers, as well:
C18 §7.17.7.5 ¶3:
For signed integer types, arithmetic is defined to use two’s complement representation with
silent wrap-around on overflow; there are no undefined results.
In the synopsis, above, A is an atomic type, and M is the corresponding non-atomic type for A (or ptrdiff_t
for atomic pointers), and C is the corresponding non-atomic type for A.
For example, here are some operations on an atomic_int.
atomic_fetch_add(&x, 20);
atomic_fetch_sub(&x, 37);
atomic_fetch_xor(&x, 3490);
They are the same as +=, -=, |=, ^= and &=, except the return value is the previous value of the atomic
object. (With the assignment operators, the value of the expression is that after its evaluation.)
atomic_int x = 10;
int prev = atomic_fetch_add(&x, 20);
printf("%d %d\n", prev, x); // 10 30
versus:
atomic_int x = 10;
int prev = (x += 20);
printf("%d %d\n", prev, x); // 30 30
And, of course, the _explicit version allows you to specify a memory order and all the assignment
operators are memory_order_seq_cst.
Return Value
Returns the previous value of the atomic object before the modification.
Example
474 Chapter 57. <stdatomic.h> Atomic-Related Functions
1 #include <stdio.h>
2 #include <stdatomic.h>
3
4 int main(void)
5 {
6 atomic_int x = 0;
7 int prev;
8
9 atomic_fetch_add(&x, 3490);
10 atomic_fetch_sub(&x, 12);
11 atomic_fetch_xor(&x, 444);
12 atomic_fetch_or(&x, 12);
13 prev = atomic_fetch_and(&x, 42);
14
See Also
atomic_exchange(), atomic_exchange_explicit(), atomic_compare_exchange_strong(),
atomic_compare_exchange_strong_explicit(), atomic_compare_exchange_weak(),
atomic_compare_exchange_weak_explicit()
57.16 atomic_flag_test_and_set()
Test and set an atomic flag
Synopsis
#include <stdatomic.h>
Description
One of the venerable old functions of lock-free programming, this function sets the given atomic flag in
object, and returns the previous value of the flag.
Return Value
Returns true if the flag was set previously, and false if it wasn’t.
Example
Using test-and-set to implement a spin lock6 :
6
Don’t use this unless you know what you’re doing—use the thread mutex functionality instead. It’ll let your blocked thread
sleep and stop chewing up CPU.
57.16. atomic_flag_test_and_set() 475
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
10 atomic_flag f = ATOMIC_FLAG_INIT;
11
18 while (atomic_flag_test_and_set(&f));
19
30 return 0;
31 }
32
33 int main(void)
34 {
35 thrd_t t1, t2;
36 int tid[] = {0, 1};
37
41 thrd_join(t1, NULL);
42 thrd_join(t2, NULL);
43 }
See Also
atomic_flag_clear()
476 Chapter 57. <stdatomic.h> Atomic-Related Functions
57.17 atomic_flag_clear()
Clear an atomic flag
Synopsis
#include <stdatomic.h>
Description
Clears an atomic flag.
As usual, the _explicit allows you to specify an alternate memory order.
Return Value
Returns nothing!
Example
Using test-and-set to implement a spin lock7 :
1 #include <stdio.h>
2 #include <threads.h>
3 #include <stdatomic.h>
4
10 atomic_flag f = ATOMIC_FLAG_INIT;
11
18 while (atomic_flag_test_and_set(&f));
19
7
Don’t use this unless you know what you’re doing—use the thread mutex functionality instead. It’ll let your blocked thread
sleep and stop chewing up CPU.
57.17. atomic_flag_clear() 477
30 return 0;
31 }
32
33 int main(void)
34 {
35 thrd_t t1, t2;
36 int tid[] = {0, 1};
37
41 thrd_join(t1, NULL);
42 thrd_join(t2, NULL);
43 }
See Also
atomic_flag_test_and_set()
478 Chapter 57. <stdatomic.h> Atomic-Related Functions
Chapter 58
This is a small header file that defines a number of convenient Boolean macros. If you really need that
kind of thing.
Macro Description
bool Type for Boolean, expands to _Bool
true True value, expands to 1
false False value, expands to 0
There’s one more macro that I’m not putting in the table because it’s such a long name it’ll blow up the
table alignment:
__bool_true_false_are_defined
which expands to 1.
58.1 Example
Here’s a lame example that shows off these macros.
1 #include <stdio.h>
2 #include <stdbool.h>
3
4 int main(void)
5 {
6 bool x;
7
8 x = (3 > 2);
9
10 if (x == true)
11 printf("The universe still makes sense.\n");
12
13 x = false;
14
Output:
The universe still makes sense.
x is now 0
479
480 Chapter 58. <stdbool.h> Boolean Types
58.2 _Bool?
What’s the deal with _Bool? Why didn’t they just make it bool?
Well, there was a lot of C code out there where people had defined their own bool type and adding an
official bool would have broken those typedefs.
But C has already reserved all identifiers that start with an underscore followed by a capital letter, so it
was clear to make up a new _Bool type and go with that.
And, if you know your code can handle it, you can include this header to get all this juicy syntax.
One more note on conversions: unlike converting to int, the only thing that converts to false in a _Bool
is a scalar zero value. Anything at all that’s not zero, like -3490, 0.12, or NaN, converts to true.
Chapter 59
Name Description
ptrdiff_t Signed integer difference between two pointers
size_t Unsigned integer type returned by sizeof
max_align_t Declare a type with the biggest possible alignment
wchar_t Wide character type
NULL NULL pointer, as defined a number of places
offsetof Get the byte offsets of struct or union fields
59.1 ptrdiff_t
This holds the different between two pointers. You could store this in another type, but the result
of a pointer subtraction is an implementation-defined type; you can be maximally portable by using
ptrdiff_t.
1 #include <stdio.h>
2 #include <stddef.h>
3
4 int main(void)
5 {
6 int cats[100];
7
11 ptrdiff_t d = g - f; // difference is 40
And you can print it by prefixing the integer format specifier with t:
13 printf("%td\n", d); // Print decimal: 40
14 printf("%tX\n", d); // Print hex: 28
15 }
59.2 size_t
This is the type returned by sizeof and used in a few other places. It’s an unsigned integer.
481
482 Chapter 59. <stddef.h> A Few Standard Definitions
6 int main(void)
7 {
8 size_t x;
9
10 x = sizeof(int);
11
12 printf("%zu\n", x);
Some functions return negative numbers cast to size_t as error values (such as mbrtoc16()). If you
want to print these as negative values, you can do it with %zd:
14 char16_t a;
15 mbstate_t mbs;
16 memset(&mbs, 0, sizeof mbs);
17
20 printf("%zd\n", x);
21 }
59.3 max_align_t
As far as I can tell, this exists to allow the runtime computation of the maximum fundamental alignment1
on the current platform. Someone please mail me if there’s another use.
Maybe you need this if you’re writing your own memory allocator or somesuch.
1 #include <stddef.h>
2 #include <stdio.h> // For printf()
3 #include <stdalign.h> // For alignof
4
5 int main(void)
6 {
7 int max = alignof(max_align_t);
8
59.4 wchar_t
This is analogous to char, except it’s for wide characters.
It’s an integer type that has enough range to hold unique values for all characters in all supported locales.
The value 0 is the wide NUL character.
1
https://en.wikipedia.org/wiki/Data_structure_alignment
59.5. offsetof 483
Finally, the values of character constants from the basic character set will be the same as their correspond-
ing wchar_t values… unless __STDC_MB_MIGHT_NEQ_WC__ is defined.
59.5 offsetof
If you have a struct or union, you can use this to get the byte offset of fields within that type.
Usage is:
offsetof(type, fieldname);
4 struct foo {
5 int a;
6 char b;
7 char c;
8 float d;
9 };
10
11 int main(void)
12 {
13 printf("a: %zu\n", offsetof(struct foo, a));
14 printf("b: %zu\n", offsetof(struct foo, b));
15 printf("c: %zu\n", offsetof(struct foo, c));
16 printf("d: %zu\n", offsetof(struct foo, d));
17 }
And you can’t use offsetof on a bitfield, so don’t get your hopes up.
484 Chapter 59. <stddef.h> A Few Standard Definitions
Chapter 60
This header gives us access to (potentially) types of a fixed number of bits, or, at the very least, types that
are at least that many bits.
It also gives us handy macros to use.
int_fast8_t uint_fast8_t
int_fast16_t uint_fast16_t
int_fast32_t uint_fast32_t
int_fast64_t uint_fast64_t
Everything else is optional, but you’ll probably also have the following, which are required when a system
has integers of these sizes with no padding and two’s-complement representation… which is the case for
Macs and PCs and a lot of other systems. In short, you very likely have these:
int8_t uint8_t
int16_t uint16_t
int32_t uint32_t
int64_t uint64_t
Other numbers of bits can also be supported by an implementation if it wants to go all crazy with it.
Examples:
#include <stdint.h>
int main(void)
{
int16_t x = 32;
int_fast32_t y = 3490;
485
486 Chapter 60. <stdint.h> More Integer Types
// ...
You can convert a void* to one of these types, and back again. And the void*s will compare equal.
The use case is any place you need an integer that represents a pointer for some reason.
Also, there are a couple types that are just there to be the biggest possible integers your system supports:
intmax_t
uintmax_t
Fun fact: you can print these types with the "%jd" and "%ju" printf() format specifiers.
There are also a bunch of macros in <inttypes.h>(#inttypes) that you can use to print any of the types
mentioned, above.
60.3 Macros
The following macros define the minimum and maximum values for these types:
INT8_MAX INT8_MIN UINT8_MAX
INT16_MAX INT16_MIN UINT16_MAX
INT32_MAX INT32_MIN UINT32_MAX
INT64_MAX INT64_MIN UINT64_MAX
For the exact-bit-size signed types, the minimum is exactly −(2𝑁−1 ) and the maximum is exactly 2𝑁−1 −
1. And for the exact-bit-size unsigned types, the max is exactly 2𝑁 − 1.
For the signed “least” and “fast” variants, the magnitude and sign of the minimum is at least −(2𝑁−1 −1)
and the maximum is at least 2𝑁−1 − 1. And for unsigned it’s at least 2𝑁 − 1.
INTMAX_MAX is at least 263 − 1, INTMAX_MIN is at least −(263 − 1) in sign and magnitude. And UINT-
MAX_MAX is at least 264 − 1.
Finally, INTPTR_MAX is at least 215 − 1, INTPTR_MIN is at least −(215 − 1) in sign and magnitude. And
UINTPTR_MAX is at least 216 − 1.
60.4. Other Limits 487
Macro Description
PTRDIFF_MIN Minimum ptrdiff_t value
PTRDIFF_MAX Maximum ptrdiff_t value
SIG_ATOMIC_MIN Minimum sig_atomic_t value
SIG_ATOMIC_MAX Maximum sig_atomic_t value
SIZE_MAX Maximum size_t value
WCHAR_MIN Minimum wchar_t value
WCHAR_MAX Maximum wchar_t value
WINT_MIN Minimum wint_t value
WINT_MAX Maximum wint_t value
The spec says that PTRDIFF_MIN will be at least -65535 in magnitude. And PTRDIFF_MAX and SIZE_MAX
will be at least 65535.
SIG_ATOMIC_MIN and MAX will be either -127 and 127 (if it’s signed) or 0 and 255 (if it’s unsigned).
You can use the macros INTN _C() and UINTN () where N is 8, 16, 32 or 64.
uint_least16_t x = INT16_C(3490);
uint_least64_t y = INT64_C(1122334455);
A variant on these is INTMAX_C() and UINTMAX_C(). They will make a constant suitable for storing in
an intmax_t or uintmax_t.
intmax_t x = INTMAX_C(3490);
uintmax_t x = UINTMAX_C(1122334455);
488 Chapter 60. <stdint.h> More Integer Types
Chapter 61
Function Description
clearerr() Clear the feof and ferror status flags
fclose() Close an open file
feof() Return the file end-of-file status
ferror() Return the file error status
fflush() Flush all buffered output to a file
fgetc() Read a character in a file
fgetpos() Get the file I/O position
fgets() Read a line from a file
fopen() Open a file
fprintf() Print formatted output to a file
fputc() Print a character to a file
fputs() Print a string to a file
fread() Read binary data from a file
freopen() Change file associated with a stream
fscanf() Read formatted input from a file
fseek() Set the file I/O position
fsetpos() Set the file I/O position
ftell() Get the file I/O position
fwrite() Write binary data to a file
getc() Get a character from stdin
getchar() Get a character from stdin
gets() Get a string from stdin (removed in C11)
perror() Print a human-formatted error message
printf() Print formatted output to stdout
putc() Print a character to stdout
putchar() Print a character to stdout
puts() Print a string to stdout
remove() Delete a file from disk
rename() Rename or move a file on disk
rewind() Set the I/O position to the beginning of a file
scanf() Read formatted input from stdin
setbuf() Configure buffering for I/O operations
setvbuf() Configure buffering for I/O operations
snprintf() Print length-limited formatted output to a string
sprintf() Print formatted output to a string
sscanf() Read formatted input from a string
tmpfile() Create a temporary file
tmpnam() Generate a unique name for a temporary file
ungetc() Push a character back on the input stream
489
490 Chapter 61. <stdio.h> Standard I/O Library
Function Description
vfprintf() Variadic print formatted output to a file
vfscanf() Variadic read formatted input from a file
vprintf() Variadic print formatted output to stdout
vscanf() Variadic read formatted input from stdin
vsnprintf() Variadic length-limited print formatted output to a
string
vsprintf() Variadic print formatted output to a string
vsscanf() Variadic read formatted input to a string
The most basic of all libraries in the whole of the standard C library is the standard I/O library. It’s used
for reading from and writing to files. I can see you’re very excited about this.
So I’ll continue. It’s also used for reading and writing to the console, as we’ve already often seen with the
printf() function.
(A little secret here—many many things in various operating systems are secretly files deep down, and
the console is no exception. “Everything in Unix is a file!” :-))
You’ll probably want some prototypes of the functions you can use, right? To get your grubby little mittens
on those, you’ll want to include stdio.h.
Anyway, so we can do all kinds of cool stuff in terms of file I/O. LIE DETECTED. Ok, ok. We can do all
kinds of stuff in terms of file I/O. Basically, the strategy is this:
1. Use fopen() to get a pointer to a file structure of type FILE*. This pointer is what you’ll be passing
to many of the other file I/O calls.
2. Use some of the other file calls, like fscanf(), fgets(), fprintf(), or etc. using the FILE*
returned from fopen().
3. When done, call fclose() with the FILE*. This let’s the operating system know that you’re truly
done with the file, no take-backs.
What’s in the FILE*? Well, as you might guess, it points to a struct that contains all kinds of information
about the current read and write position in the file, how the file was opened, and other stuff like that. But,
honestly, who cares. No one, that’s who. The FILE structure is opaque to you as a programmer; that is,
you don’t need to know what’s in it, and you don’t even want to know what’s in it. You just pass it to the
other standard I/O functions and they know what to do.
This is actually pretty important: try to not muck around in the FILE structure. It’s not even the same
from system to system, and you’ll end up writing some really non-portable code.
One more thing to mention about the standard I/O library: a lot of the functions that operate on files use
an “f” prefix on the function name. The same function that is operating on the console will leave the “f”
off. For instance, if you want to print to the console, you use printf(), but if you want to print to a file,
use fprintf(), see?
Wait a moment! If writing to the console is, deep down, just like writing to a file, since everything in Unix
is a file, why are there two functions? Answer: it’s more convenient. But, more importantly, is there a
FILE* associated with the console that you can use? Answer: YES!
There are, in fact, three (count ’em!) special FILE*s you have at your disposal merely for just including
stdio.h. There is one for input, and two for output.
That hardly seems fair—why does output get two files, and input only get one?
That’s jumping the gun a bit—let’s just look at them:
Stream Description
stdin Input from the console.
stdout Output to the console.
61.1. remove() 491
Stream Description
stderr Output to the console on the error file stream.
So standard input (stdin) is by default just what you type at the keyboard. You can use that in fscanf()
if you want, just like this:
/* this line: */
scanf("%d", &x);
So what is this stderr thing? What happens when you output to that? Well, generally it goes to the
console just like stdout, but people use it for error messages, specifically. Why? On many systems
you can redirect the output from the program into a file from the command line…and sometimes you’re
interested in getting just the error output. So if the program is good and writes all its errors to stderr, a
user can redirect just stderr into a file, and just see that. It’s just a nice thing you, as a programmer, can
do.
Finally, a lot of these functions return int where you might expect char. This is because the function can
return a character or end-of-file (EOF), and EOF is potentially an integer. If you don’t get EOF as a return
value, you can safely store the result in a char.
61.1 remove()
Delete a file
Synopsis
#include <stdio.h>
Description
Removes the specified file from the filesystem. It just deletes it. Nothing magical. Simply call this
function and sacrifice a small chicken and the requested file will be deleted.
Return Value
Returns zero on success, and -1 on error, setting errno.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char *filename = "evidence.txt";
6
492 Chapter 61. <stdio.h> Standard I/O Library
7 remove(filename);
8 }
See Also
rename()
61.2 rename()
Renames a file and optionally moves it to a new location
Synopsis
#include <stdio.h>
Description
Renames the file old to name new. Use this function if you’re tired of the old name of the file, and you
are ready for a change. Sometimes simply renaming your files makes them feel new again, and could save
you money over just getting all new files!
One other cool thing you can do with this function is actually move a file from one directory to another
by specifying a different path for the new name.
Return Value
Returns zero on success, and -1 on error, setting errno.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 // Rename a file
6 rename("foo", "bar");
7
See Also
remove()
61.3 tmpfile()
Create a temporary file
61.4. tmpnam() 493
Synopsis
#include <stdio.h>
FILE *tmpfile(void);
Description
This is a nifty little function that will create and open a temporary file for you, and will return a FILE* to
it that you can use. The file is opened with mode “r+b”, so it’s suitable for reading, writing, and binary
data.
By using a little magic, the temp file is automatically deleted when it is close()’d or when your program
exits. (Specifically, in Unix terms, tmpfile() unlinks1 the file right after it opens it. This means that
it’s primed to be deleted from disk, but still exists because your process still has it open. As soon as your
process exits, all open files are closed, and the temp file vanishes into the ether.)
Return Value
This function returns an open FILE* on success, or NULL on failure.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *temp;
6 char s[128];
7
8 temp = tmpfile();
9
See Also
fopen(), fclose(), tmpnam()
61.4 tmpnam()
Generate a unique name for a temporary file
Synopsis
#include <stdio.h>
1
https://man.archlinux.org/man/unlinkat.2.en#DESCRIPTION
494 Chapter 61. <stdio.h> Standard I/O Library
Description
This function takes a good hard look at the existing files on your system, and comes up with a unique
name for a new file that is suitable for temporary file usage.
Let’s say you have a program that needs to store off some data for a short time so you create a temporary
file for the data, to be deleted when the program is done running. Now imagine that you called this file
foo.txt. This is all well and good, except what if a user already has a file called foo.txt in the directory
that you ran your program from? You’d overwrite their file, and they’d be unhappy and stalk you forever.
And you wouldn’t want that, now would you?
Ok, so you get wise, and you decide to put the file in /tmp so that it won’t overwrite any important content.
But wait! What if some other user is running your program at the same time and they both want to use
that filename? Or what if some other program has already created that file?
See, all of these scary problems can be completely avoided if you just use tmpnam() to get a safe-ready-
to-use filename.
So how do you use it? There are two amazing ways. One, you can declare an array (or malloc() it—
whatever) that is big enough to hold the temporary file name. How big is that? Fortunately there has been
a macro defined for you, L_tmpnam, which is how big the array must be.
And the second way: just pass NULL for the filename. tmpnam() will store the temporary name in a static
array and return a pointer to that. Subsequent calls with a NULL argument will overwrite the static array,
so be sure you’re done using it before you call tmpnam() again.
Again, this function just makes a file name for you. It’s up to you to later fopen() the file and use it.
One more note: some compilers warn against using tmpnam() since some systems have better functions
(like the Unix function mkstemp().) You might want to check your local documentation to see if there’s
a better option. Linux documentation goes so far as to say, “Never use this function. Use mkstemp()
instead.”
I, however, am going to be a jerk and not talk about mkstemp()2 because it’s not in the standard I’m
writing about. Nyaah.
The macro TMP_MAX holds the number of unique filenames that can be generated by tmpnam(). Ironically,
it is the minimum number of such filenames.
Return Value
Returns a pointer to the temporary file name. This is either a pointer to the string you passed in, or a
pointer to internal static storage if you passed in NULL. On error (like it can’t find any temporary name
that is unique), tmpnam() returns NULL.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char filename[L_tmpnam];
6 char *another_filename;
7
8 if (tmpnam(filename) != NULL)
9 printf("We got a temp file name: \"%s\"\n", filename);
10 else
11 printf("Something went wrong, and we got nothing!\n");
12
13 another_filename = tmpnam(NULL);
14
2
https://man.archlinux.org/man/mkstemp.3.en
61.5. fclose() 495
See Also
fopen(), tmpfile()
61.5 fclose()
The opposite of fopen()—closes a file when you’re done with it so that it frees system resources
Synopsis
#include <stdio.h>
Description
When you open a file, the system sets aside some resources to maintain information about that open file.
Usually it can only open so many files at once. In any case, the Right Thing to do is to close your files
when you’re done using them so that the system resources are freed.
Also, you might not find that all the information that you’ve written to the file has actually been written
to disk until the file is closed. (You can force this with a call to fflush().)
When your program exits normally, it closes all open files for you. Lots of times, though, you’ll have
a long-running program, and it’d be better to close the files before then. In any case, not closing a file
you’ve opened makes you look bad. So, remember to fclose() your file when you’re done with it!
Return Value
On success, 0 is returned. Typically no one checks for this. On error EOF is returned. Typically no one
checks for this, either.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6
7 fp = fopen("spoon.txt", "r");
8
9 if (fp == NULL) {
10 printf("Error opening file\n");
11 } else {
12 printf("Opened file just fine!\n");
496 Chapter 61. <stdio.h> Standard I/O Library
See Also
fopen()
61.6 fflush()
Process all buffered I/O for a stream right now
Synopsis
#include <stdio.h>
Description
When you do standard I/O, as mentioned in the section on the setvbuf() function, it is usually stored
in a buffer until a line has been entered or the buffer is full or the file is closed. Sometimes, though, you
really want the output to happen right this second, and not wait around in the buffer. You can force this
to happen by calling fflush().
The advantage to buffering is that the OS doesn’t need to hit the disk every time you call fprintf().
The disadvantage is that if you look at the file on the disk after the fprintf() call, it might not have
actually been written to yet. (“I called fputs(), but the file is still zero bytes long! Why?!”) In virtually
all circumstances, the advantages of buffering outweigh the disadvantages; for those other circumstances,
however, use fflush().
Note that fflush() is only designed to work on output streams according to the spec. What will happen
if you try it on an input stream? Use your spooky voice: who knooooows!
Return Value
On success, fflush() returns zero. If there’s an error, it returns EOF and sets the error condition for the
stream (see ferror().)
Example
In this example, we’re going to use the carriage return, which is '\r'. This is like newline ('\n'), except
that it doesn’t move to the next line. It just returns to the front of the current line.
What we’re going to do is a little text-based status bar like so many command line programs implement.
It’ll do a countdown from 10 to 0 printing over itself on the same line.
What is the catch and what does this have to do with fflush()? The catch is that the terminal is most
likely “line buffered” (see the section on setvbuf() for more info), meaning that it won’t actually display
anything until it prints a newline. But we’re not printing newlines; we’re just printing carriage returns, so
we need a way to force the output to occur even though we’re on the same line. Yes, it’s fflush()!
1 #include <stdio.h>
2 #include <threads.h>
3
4 void sleep_seconds(int s)
5 {
61.7. fopen() 497
9 int main(void)
10 {
11 int count;
12
23 sleep_seconds(1);
24 }
25 }
See Also
setbuf(), setvbuf()
61.7 fopen()
Opens a file for reading or writing
Synopsis
#include <stdio.h>
Description
The fopen() opens a file for reading or writing.
Parameter path can be a relative or fully-qualified path and file name to the file in question.
Parameter mode tells fopen() how to open the file (reading, writing, or both), and whether or not it’s a
binary file. Possible modes are:
Mode Description
r Open the file for reading (read-only).
w Open the file for writing (write-only). The file is
created if it doesn’t exist.
r+ Open the file for reading and writing. The file has
to already exist.
w+ Open the file for writing and reading. The file is
created if it doesn’t already exist.
498 Chapter 61. <stdio.h> Standard I/O Library
Mode Description
a Open the file for append. This is just like opening
a file for writing, but it positions the file pointer at
the end of the file, so the next write appends to the
end. The file is created if it doesn’t exist.
a+ Open the file for reading and appending. The file
is created if it doesn’t exist.
Any of the modes can have the letter “b” appended to the end, as is “wb” (“write binary”), to signify
that the file in question is a binary file. (“Binary” in this case generally means that the file contains
non-alphanumeric characters that look like garbage to human eyes.) Many systems (like Unix) don’t
differentiate between binary and non-binary files, so the “b” is extraneous. But if your data is binary, it
doesn’t hurt to throw the “b” in there, and it might help someone who is trying to port your code to another
system.
The macro FOPEN_MAX tells you how many streams (at least) you can have open at once.
The macro FILENAME_MAX tells you what the longest valid filename can be. Don’t go crazy, now.
Return Value
fopen() returns a FILE* that can be used in subsequent file-related calls.
If something goes wrong (e.g. you tried to open a file for read that didn’t exist), fopen() will return NULL.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6
7 fp = fopen("spoon.txt", "r");
8
9 if (fp == NULL) {
10 printf("Error opening file\n");
11 } else {
12 printf("Opened file just fine!\n");
13 fclose(fp); // All done!
14 }
15 }
See Also
fclose(), freopen()
61.8 freopen()
Reopen an existing FILE*, associating it with a new path
Synopsis
61.8. freopen() 499
#include <stdio.h>
Description
Let’s say you have an existing FILE* stream that’s already open, but you want it to suddenly use a different
file than the one it’s using. You can use freopen() to “re-open” the stream with a new file.
Why on Earth would you ever want to do that? Well, the most common reason would be if you had a
program that normally would read from stdin, but instead you wanted it to read from a file. Instead of
changing all your scanf()s to fscanf()s, you could simply reopen stdin on the file you wanted to read
from.
Another usage that is allowed on some systems is that you can pass NULL for filename, and specify a new
mode for stream. So you could change a file from “r+” (read and write) to just “r” (read), for instance.
It’s implementation dependent which modes can be changed.
When you call freopen(), the old stream is closed. Otherwise, the function behaves just like the stan-
dard fopen().
Return Value
freopen() returns stream if all goes well.
If something goes wrong (e.g. you tried to open a file for read that didn’t exist), freopen() will return
NULL.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i, i2;
6
See Also
fclose(), fopen()
500 Chapter 61. <stdio.h> Standard I/O Library
Synopsis
#include <stdio.h>
Description
Now brace yourself because this might come as a bit of a surprise to you: when you printf() or
fprintf() or use any I/O functions like that, it does not normally work immediately. For the sake of
efficiency, and to irritate you, the I/O on a FILE* stream is buffered away safely until certain conditions
are met, and only then is the actual I/O performed. The functions setbuf() and setvbuf() allow you
to change those conditions and the buffering behavior.
So what are the different buffering behaviors? The biggest is called “full buffering”, wherein all I/O is
stored in a big buffer until it is full, and then it is dumped out to disk (or whatever the file is). The next
biggest is called “line buffering”; with line buffering, I/O is stored up a line at a time (until a newline
('\n') character is encountered) and then that line is processed. Finally, we have “unbuffered”, which
means I/O is processed immediately with every standard I/O call.
You might have seen and wondered why you could call putchar() time and time again and not see any
output until you called putchar('\n'); that’s right—stdout is line-buffered!
Since setbuf() is just a simplified version of setvbuf(), we’ll talk about setvbuf() first.
The stream is the FILE* you wish to modify. The standard says you must make your call to setvbuf()
before any I/O operation is performed on the stream, or else by then it might be too late.
The next argument, buf allows you to make your own buffer space (using malloc() or just a char array)
to use for buffering. If you don’t care to do this, just set buf to NULL.
Now we get to the real meat of the function: mode allows you to choose what kind of buffering you want
to use on this stream. Set it to one of the following:
Mode Description
_IOFBF stream will be fully buffered.
_IOLBF stream will be line buffered.
_IONBF stream will be unbuffered.
Finally, the size argument is the size of the array you passed in for buf…unless you passed NULL for
buf, in which case it will resize the existing buffer to the size you specify.
Now what about this lesser function setbuf()? It’s just like calling setvbuf() with some specific
parameters, except setbuf() doesn’t return a value. The following example shows the equivalency:
// these are the same:
setbuf(stream, buf);
setvbuf(stream, buf, _IOFBF, BUFSIZ); // fully buffered
Return Value
setvbuf() returns zero on success, and nonzero on failure. setbuf() has no return value.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 char lineBuf[1024];
7
8 fp = fopen("somefile.txt", "w");
9 setvbuf(fp, lineBuf, _IOLBF, 1024); // set to line buffering
10 fprintf(fp, "You won't see this in the file yet. ");
11 fprintf(fp, "But now you will because of this newline.\n");
12 fclose(fp);
13
14 fp = fopen("anotherfile.txt", "w");
15 setbuf(fp, NULL); // set to unbuffered
16 fprintf(fp, "You will see this in the file now.");
17 fclose(fp);
18 }
See Also
fflush()
Synopsis
#include <stdio.h>
Description
These functions print formatted output to a variety of destinations.
The only differences between these is are the leading parameters that you pass to them before the format
string.
The printf() function is legendary as being one of the most flexible outputting systems ever devised. It
can also get a bit freaky here or there, most notably in the format string. We’ll take it a step at a time
here.
The easiest way to look at the format string is that it will print everything in the string as-is, unless a
character has a percent sign (%) in front of it. That’s when the magic happens: the next argument in the
printf() argument list is printed in the way described by the percent code. These percent codes are
called format specifiers.
Here are the most common format specifiers.
Specifier Description
%d Print the next argument as a signed decimal number, like 3490. The argument printed
this way should be an int, or something that gets promoted to int.
%f Print the next argument as a signed floating point number, like 3.14159. The argument
printed this way should be a double, or something that gets promoted to a double.
%c Print the next argument as a character, like 'B'. The argument printed this way should
be a char variant.
%s Print the next argument as a string, like "Did you remember your mittens?". The
argument printed this way should be a char* or char[].
%% No arguments are converted, and a plain old run-of-the-mill percent sign is printed.
This is how you print a ‘%’ using printf().
So those are the basics. I’ll give you some more of the format specifiers in a bit, but let’s get some more
breadth before then. There’s actually a lot more that you can specify in there after the percent sign.
For one thing, you can put a field width in there—this is a number that tells printf() how many spaces
to put on one side or the other of the value you’re printing. That helps you line things up in nice columns.
If the number is negative, the result becomes left-justified instead of right-justified. Example:
printf("%10d", x); /* prints X on the right side of the 10-space field */
printf("%-10d", x); /* prints X on the left side of the 10-space field */
If you don’t know the field width in advance, you can use a little kung-foo to get it from the argument list
just before the argument itself. Do this by placing your seat and tray tables in the fully upright position.
The seatbelt is fastened by placing the—cough. I seem to have been doing way too much flying lately.
Ignoring that useless fact completely, you can specify a dynamic field width by putting a * in for the width.
If you are not willing or able to perform this task, please notify a flight attendant and we will reseat you.
int width = 12;
int value = 3490;
You can also put a “0” in front of the number if you want it to be padded with zeros:
int x = 17;
printf("%05d", x); /* "00017" */
61.10. printf(), fprintf(), sprintf(), snprintf() 503
When it comes to floating point, you can also specify how many decimal places to print by making a field
width of the form “x.y” where x is the field width (you can leave this off if you want it to be just wide
enough) and y is the number of digits past the decimal point to print:
float f = 3.1415926535;
Ok, those above are definitely the most common uses of printf(), but let’s get total coverage.
Conversion
Specifier Description
d Print an int argument as a decimal number.
i Identical to d.
o Print an unsigned int in octal (base 8).
u Print an unsigned int in decimal.
x Print an unsigned int in hexadecimal with lowercase letters.
X Print an unsigned int in hexadecimal with uppercase letters.
f Print a double in decimal notation. Infinity is printed as infinity or inf, and NaN is
printed as nan, any of which could have a leading minus sign.
F Same as f, except it prints out INFINITY, INF, or NAN in all caps.
e Print a number in scientific notation, e.g. 1.234e56. Does infinity and NaN like f.
E Just like e, except prints the exponent E (and infinity and NaN) in uppercase.
g Print small numbers like f and large numbers like e. See note below.
G Print small numbers like F and large numbers like E. See note below.
a Print a double in hexadecimal form 0xh.hhhhpd where h is a lowercase hex digit and
d is a decimal exponent of 2. Infinity and NaN in the form of f. More below.
A Like a except everything’s uppercase.
c Convert int argument to unsigned char and print as a character.
s Print a string starting at the given char*.
p Print a void* out as a number, probably the numeric address, possibly in hex.
n Store the number of characters written so far in the given int*. Doesn’t print anything.
See below.
% Print a literal percent sign.
61.10.0.2.1 Note on %a and %A When printing floating point numbers in hex form, there is one number
before the decimal point, and the rest of are out to the precision.
504 Chapter 61. <stdio.h> Standard I/O Library
double pi = 3.14159265358979;
C can choose the leading number in such a way to ensure subsequent digits align to 4-bit boundaries.
If the precision is left out and the macro FLT_RADIX is a power of 2, enough precision is used to represent
the number exactly. If FLT_RADIX is not a power of two, enough precision is used to be able to tell any
two floating values apart.
If the precision is 0 and the # flag isn’t specified, the decimal point is omitted.
61.10.0.2.2 Note on %g and %G The gist of this is to use scientific notation when the number gets too
“extreme”, and regular decimal notation otherwise.
The exact behavior for whether these print as %f or %e depends on a number of factors:
If the number’s exponent is greater than or equal to -4 and the precision is greater than the exponent, we
use %f. In this case, the precision is converted according to 𝑝 = 𝑝 − (𝑥 + 1), where 𝑝 is the specified
precision and 𝑥 is the exponent.
Otherwise we use %e, and the precision becomes 𝑝 − 1.
Trailing zeros in the decimal portion are removed. And if there are none left, the decimal point is removed,
too. All this unless the # flag is specified.
61.10.0.2.3 Note on %n This specifier is cool and different, and rarely needed. It doesn’t actually print
anything, but stores the number of characters printed so far in the next pointer argument in the list.
int numChars;
float a = 3.14159;
int b = 3490;
The above example will print out the values of a and b, and then store the number of characters printed
so far into the variable numChars. The next call to printf() prints out that result.
3.141590 3490
The above line contains 13 characters
Length
Modifier Conversion Specifier Description
hh d, i, o, u, x, X Convert argument to char (signed or unsigned as
appropriate) before printing.
h d, i, o, u, x, X Convert argument to short int (signed or unsigned as
appropriate) before printing.
l d, i, o, u, x, X Argument is a long int (signed or unsigned as appropriate).
ll d, i, o, u, x, X Argument is a long long int (signed or unsigned as
appropriate).
61.10. printf(), fprintf(), sprintf(), snprintf() 505
Length
Modifier Conversion Specifier Description
j d, i, o, u, x, X Argument is a intmax_t or uintmax_t (as appropriate).
z d, i, o, u, x, X Argument is a size_t.
t d, i, o, u, x, X Argument is a ptrdiff_t.
L a, A, e, E, f, F, g, G Argument is a long double.
l c Argument is in a wint_t, a wide character.
l s Argument is in a wchar_t*, a wide character string.
hh n Store result in signed char* argument.
h n Store result in short int* argument.
l n Store result in long int* argument.
ll n Store result in long long int* argument.
j n Store result in intmax_t* argument.
z n Store result in size_t* argument.
t n Store result in ptrdiff_t* argument.
61.10.0.4 Precision
In front of the length modifier, you can put a precision, which generally means how many decimal places
you want on your floating point numbers.
To do this, you put a decimal point (.) and the decimal places afterward.
For example, we could print π rounded to two decimal places like this:
double pi = 3.14159265358979;
If no number is specified in the precision after the decimal point, the precision is zero.
If an * is specified after the decimal, something amazing happens! It means the int argument to printf()
before the number to be printed holds the precision. You can use this if you don’t know the precision at
compile time.
int precision;
double pi = 3.14159265358979;
Which gives:
Enter precision: 4
3.1416
506 Chapter 61. <stdio.h> Standard I/O Library
<< 3490>>
<<3490 >>
Like with the precision, you can use an asterisk (*) as the field width
int field_width;
int val = 3490;
61.10.0.6 Flags
Before the field width, you can put some optional flags that further control the output of the subsequent
fields. We just saw that the - flag can be used to left- or right-justify fields. But there are plenty more!
Flag Description
- For a field width, left justify in the field (right is default).
+ If the number is signed, always prefix a + or - on the front.
[SPACE] If the number is signed, prefix a space for positive, or a - for negative.
0 Pad the right-justified field with leading zeros instead of leading spaces.
# Print using an alternate form. See below.
For example, we could pad a hexadecimal number with leading zeros to a field width of 8 with:
printf("%08x\n", 0x1234); // 00001234
snprintf() always terminates the string with a NUL character. So if you try to write out more than the
maximum specified characters, the universe ends.
Just kidding. If you do, snprintf() will write 𝑛 − 1 characters so that it has enough room to write the
terminator at the end.
Return Value
Returns the number of characters outputted, or a negative number on error.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int a = 100;
6 float b = 2.717;
7 char *c = "beej!";
8 char d = 'X';
9 int e = 5;
10
See Also
sprintf(), vprintf()
Synopsis
#include <stdio.h>
Description
These functions read formatted output from a variety of sources.
The only differences between these is are the leading parameters that you pass to them before the format
string.
The scanf() family of functions reads data from the console or from a FILE stream, parses it, and stores
the results away in variables you provide in the argument list.
The format string is very similar to that in printf() in that you can tell it to read a "%d", for instance for
an int. But it also has additional capabilities, most notably that it can eat up other characters in the input
that you specify in the format string.
But let’s start simple, and look at the most basic usage first before plunging into the depths of the function.
We’ll start by reading an int from the keyboard:
int a;
scanf("%d", &a);
scanf() obviously needs a pointer to the variable if it is going to change the variable itself, so we use the
address-of operator to get the pointer.
In this case, scanf() walks down the format string, finds a “%d”, and then knows it needs to read an
integer and store it in the next variable in the argument list, a.
Here are some of the other format specifiers you can put in the format string:
In that case, scanf() will attempt to consume an unsigned decimal number, then a hyphen, then another
unsigned number, then another hypen, then another unsigned number.
If it fails to match at any point (e.g. the user entered “foo”), scanf() will bail without consuming the
offending characters.
And it will return the number of variables successfully converted. In the example above, if the user entered
a valid string, scanf() would return 3, one for each variable successfully read.
Conversion
Specifier Description
d Matches a decimal int. Can have a leading sign.
i Like d, except will handle it if you put a leading 0x (hex) or 0 (octal) on the number.
o Matches an octal (base 8) unsigned int. Leading zeros are ignored.
u Matches a decimal unsigned int.
x Matches a hex (base 16) unsigned int.
f Match a floating point number (or scientific notation, or anything strtod() can
handle).
c Match a char, or mutiple chars if a field width is given.
s Match a sequence of non-whitespace chars.
[ Match a sequence of characters from a set. The set ends with ]. More below.
p Match a pointer, the opposite of %p for printf().
n Store the number of characters written so far in the given int*. Doesn’t consume
anything.
% Match a literal percent sign.
61.11.0.5.1 The Scanset %[] Conversion Specifier This is about the weirdest format specifier there
is. It allows you to specify a set of characters (the scanset) to be stored away (likely in an array of chars).
Conversion stops when a character that is not in the set is matched.
For example, %[0-9] means “match all numbers zero through nine.” And %[AD-G34] means “match A,
D through G, 3, or 4”.
Now, to convolute matters, you can tell scanf() to match characters that are not in the set by putting a
caret (^) directly after the %[ and following it with the set, like this: %[^A-C], which means “match all
characters that are not A through C.”
To match a close square bracket, make it the first character in the set, like this: %[]A-C] or %[^]A-C]. (I
added the “A-C” just so it was clear that the “]” was first in the set.)
To match a hyphen, make it the last character in the set, e.g. to match A-through-C or hyphen: %[A-C-].
So if we wanted to match all letters except “%”, “^”, “]”, “B”, “C”, “D”, “E”, and “-”, we could use this
format string: %[^]%^B-E-].
Got it? Now we can go onto the next func—no wait! There’s more! Yes, still more to know about
scanf(). Does it never end? Try to imagine how I feel writing about it!
Length
Modifier Conversion Specifier Description
hh d, i, o, u, x, X Convert input to char (signed or unsigned as appropriate)
before printing.
61.11. scanf(), fscanf(), sscanf() 511
Length
Modifier Conversion Specifier Description
h d, i, o, u, x, X Convert input to short int (signed or unsigned as
appropriate) before printing.
l d, i, o, u, x, X Convert input to long int (signed or unsigned as
appropriate).
ll d, i, o, u, x, X Convert input to long long int (signed or unsigned as
appropriate).
j d, i, o, u, x, X Convert input to intmax_t or uintmax_t (as appropriate).
z d, i, o, u, x, X Convert input to size_t.
t d, i, o, u, x, X Convert input to ptrdiff_t.
L a, A, e, E, f, F, g, G Convert input to long double.
l c,s,[ Convert input to wchar_t, a wide character.
l s Argument is in a wchar_t*, a wide character string.
hh n Store result in signed char* argument.
h n Store result in short int* argument.
l n Store result in long int* argument.
ll n Store result in long long int* argument.
j n Store result in intmax_t* argument.
z n Store result in size_t* argument.
t n Store result in ptrdiff_t* argument.
Return Value
scanf() returns the number of items assigned into variables. Since assignment into variables stops when
given invalid input for a certain format specifier, this can tell you if you’ve input all your data correctly.
Also, scanf() returns EOF on end-of-file.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
512 Chapter 61. <stdio.h> Standard I/O Library
5 int a;
6 long int b;
7 unsigned int c;
8 float d;
9 double e;
10 long double f;
11 char s[100];
12
31 // store 10 characters:
32 scanf("%10c", s);
33 }
See Also
sscanf(), vscanf(), vsscanf(), vfscanf()
Synopsis
#include <stdio.h>
#include <stdarg.h>
Description
These are just like the printf() variants except instead of taking an actual variable number of arguments,
they take a fixed number—the last of which is a va_list that refers to the variable arguments.
Like with printf(), the different variants send output different places.
Both vsprintf() and vsnprintf() have the quality that if you pass in NULL as the buffer, nothing is
written—but you can still check the return value to see how many characters would have been written.
If you try to write out more than the maximum number of characters, vsnprintf() will graciously write
only 𝑛 − 1 characters so that it has enough room to write the terminator at the end.
As for why in the heck would you ever want to do this, the most common reason is to create your own
specialized versions of printf()-type functions, piggybacking on all that printf() functionality good-
ness.
See the example for an example, predictably.
Return Value
vprintf() and vfprintf() return the number of characters printed, or a negative value on error.
vsprintf() returns the number of characters printed to the buffer, not counting the NUL terminator, or
a negative value if an error occurred.
vnsprintf() returns the number of characters printed to the buffer. Or the number that would have been
printed if the buffer had been large enough.
Example
In this example, we make our own version of printf() called logger() that timestamps output. Notice
how the calls to logger() have all the bells and whistles of printf().
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <time.h>
4
16 va_start(va, format);
17 int result = vprintf(format, va);
18 va_end(va);
19
20 printf("\n");
21
514 Chapter 61. <stdio.h> Standard I/O Library
22 return result;
23 }
24
25 int main(void)
26 {
27 int x = 12;
28 float y = 3.2;
29
30 logger("Hello!");
31 logger("x = %d and y = %.2f", x, y);
32 }
Output:
2021-03-30 04:25:49 : Hello!
2021-03-30 04:25:49 : x = 12 and y = 3.20
See Also
printf()
Synopsis
#include <stdio.h>
#include <stdarg.h>
Description
These are just like the scanf() variants except instead of taking an actual variable number of arguments,
they take a fixed number—the last of which is a va_list that refers to the variable arguments.
Like with the vprintf() functions, this would be a good way to add additional functionality that took
advantage of the power scanf() has to offer.
Return Value
Returns the number of items successfully scanned, or EOF on end-of-file or error.
61.14. getc(), fgetc(), getchar() 515
Example
I have to admit I was wracking my brain to think of when you’d ever want to use this. The best example
I could find was one on Stack Overflow4 that error-checks the return value from scanf() against the
expected. A variant of that is shown below.
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <assert.h>
4
9 va_start(va, format);
10 int count = vscanf(format, va);
11 va_end(va);
12
16 return count;
17 }
18
19 int main(void)
20 {
21 int a, b;
22 float c;
23
See Also
scanf()
Synopsis
#include <stdio.h>
int getchar(void);
Description
All of these functions in one way or another, read a single character from the console or from a FILE. The
differences are fairly minor, and here are the descriptions:
4
https://stackoverflow.com/questions/17017331/c99-vscanf-for-dummies/17018046#17018046
516 Chapter 61. <stdio.h> Standard I/O Library
getc() returns a character from the specified FILE. From a usage standpoint, it’s equivalent to the same
fgetc() call, and fgetc() is a little more common to see. Only the implementation of the two functions
differs.
fgetc() returns a character from the specified FILE. From a usage standpoint, it’s equivalent to the same
getc() call, except that fgetc() is a little more common to see. Only the implementation of the two
functions differs.
Yes, I cheated and used cut-n-paste to do that last paragraph.
getchar() returns a character from stdin. In fact, it’s the same as calling getc(stdin).
Return Value
All three functions return the unsigned char that they read, except it’s cast to an int.
If end-of-file or an error is encountered, all three functions return EOF.
Example
This example reads all the characters from a file, outputting only the letter ’b’s it finds..
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 int c;
7
18 putchar('\n');
19
20 fclose(fp);
21 }
See Also
Synopsis
#include <stdio.h>
Description
These are functions that will retrieve a newline-terminated string from the console or a file. In other
normal words, it reads a line of text. The behavior is slightly different, and, as such, so is the usage. For
instance, here is the usage of gets():
Don’t use gets(). In fact, as of C11, it ceases to exist! This is one of the rare cases of a function being
removed from the standard.
Admittedly, rationale would be useful, yes? For one thing, gets() doesn’t allow you to specify the length
of the buffer to store the string in. This would allow people to keep entering data past the end of your
buffer, and believe me, this would be Bad News.
And that’s what the size parameter in fgets() is for. fgets() will read at most size-1 characters and
then stick a NUL terminator on after that.
I was going to add another reason, but that’s basically the primary and only reason not to use gets(). As
you might suspect, fgets() allows you to specify a maximum string length.
One difference here between the two functions: gets() will devour and throw away the newline at the
end of the line, while fgets() will store it at the end of your string (space permitting).
Here’s an example of using fgets() from the console, making it behave more like gets() (with the
exception of the newline inclusion):
char s[100];
gets(s); // don't use this--read a line (from stdin)
fgets(s, sizeof(s), stdin); // read a line from stdin
In this case, the sizeof() operator gives us the total size of the array in bytes, and since a char is a byte,
it conveniently gives us the total size of the array.
Of course, like I keep saying, the string returned from fgets() probably has a newline at the end that you
might not want. You can write a short function to chop the newline off—in fact, let’s just roll that into our
own version of gets()
#include <stdio.h>
#include <string.h>
if (rv == NULL)
return NULL;
return s;
}
So, in summary, use fgets() to read a line of text from the keyboard or a file, and don’t use gets().
Return Value
Both gets() and fgets() return a pointer to the string passed.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 char s[100];
7
See Also
getc(), fgetc(), getchar(), puts(), fputs(), ungetc()
Synopsis
#include <stdio.h>
Description
All three functions output a single character, either to the console or to a FILE.
putc() takes a character argument, and outputs it to the specified FILE. fputc() does exactly the same
thing, and differs from putc() in implementation only. Most people use fputc().
putchar() writes the character to the console, and is the same as calling putc(c, stdout).
Return Value
All three functions return the character written on success, or EOF on error.
Example
Print the alphabet:
61.17. puts(), fputs() 519
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char i;
6
See Also
Synopsis
#include <stdio.h>
Description
Both these functions output a NUL-terminated string. puts() outputs to the console, while fputs()
allows you to specify the file for output.
Return Value
Both functions return non-negative on success, or EOF on error.
Example
Read strings from the console and save them in a file:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6 char s[100];
7
14 fclose(fp);
15 }
520 Chapter 61. <stdio.h> Standard I/O Library
See Also
61.18 ungetc()
Pushes a character back into the input stream
Synopsis
#include <stdio.h>
Description
You know how getc() reads the next character from a file stream? Well, this is the opposite of that—it
pushes a character back into the file stream so that it will show up again on the very next read from the
stream, as if you’d never gotten it from getc() in the first place.
Why, in the name of all that is holy would you want to do that? Perhaps you have a stream of data that
you’re reading a character at a time, and you won’t know to stop reading until you get a certain character,
but you want to be able to read that character again later. You can read the character, see that it’s what
you’re supposed to stop on, and then ungetc() it so it’ll show up on the next read.
Yeah, that doesn’t happen very often, but there we are.
Here’s the catch: the standard only guarantees that you’ll be able to push back one character. Some
implementations might allow you to push back more, but there’s really no way to tell and still be portable.
Return Value
On success, ungetc() returns the character you passed to it. On failure, it returns EOF.
Example
This example reads a piece of punctuation, then everything after it up to the next piece of punctuation. It
returns the leading punctuation, and stores the rest in a string.
1 #include <stdio.h>
2 #include <ctype.h>
3
8 origpunct = fgetc(fp);
9
21 ungetc(c, fp);
22
23 return origpunct;
24 }
25
26 int main(void)
27 {
28 char s[128];
29 char c;
30
Sample Input:
!foo#bar*baz
Sample output:
!: foo
#: bar
*: baz
See Also
fgetc()
61.19 fread()
Read binary data from a file
Synopsis
#include <stdio.h>
Description
You might remember that you can call fopen() with the “b” flag in the open mode string to open the file
in “binary” mode. Files open in not-binary (ASCII or text mode) can be read using standard character-
oriented calls like fgetc() or fgets(). Files open in binary mode are typically read using the fread()
function.
All this function does is says, “Hey, read this many things where each thing is a certain number of bytes,
and store the whole mess of them in memory starting at this pointer.”
This can be very useful, believe me, when you want to do something like store 20 ints in a file.
But wait—can’t you use fprintf() with the “%d” format specifier to save the ints to a text file and store
them that way? Yes, sure. That has the advantage that a human can open the file and read the numbers.
It has the disadvantage that it’s slower to convert the numbers from ints to text and that the numbers are
likely to take more space in the file. (Remember, an int is likely 4 bytes, but the string “12345678” is 8
bytes.)
So storing the binary data can certainly be more compact and faster to read.
522 Chapter 61. <stdio.h> Standard I/O Library
Return Value
This function returns the number of items successfully read. If all requested items are read, the return
value will be equal to that of the parameter nmemb. If EOF occurs, the return value will be zero.
To make you confused, it will also return zero if there’s an error. You can use the functions feof() or
ferror() to tell which one really happened.
Example
Read 10 numbers from a file and store them in an array:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int i;
6 int n[10]
7 FILE *fp;
8
9 fp = fopen("numbers.dat", "rb");
10 fread(n, sizeof(int), 10, fp); // read 10 ints
11 fclose(fp);
12
See Also
fopen(), fwrite(), feof(), ferror()
61.20 fwrite()
Write binary data to a file
Synopsis
#include <stdio.h>
size_t fwrite(const void *p, size_t size, size_t nmemb, FILE *stream);
Description
This is the counterpart to the fread() function. It writes blocks of binary data to disk. For a description
of what this means, see the entry for fread().
Return Value
fwrite() returns the number of items successfully written, which should hopefully be nmemb that you
passed in. It’ll return zero on error.
Example
Save 10 random numbers to a file:
61.21. fgetpos(), fsetpos() 523
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 int i;
7 int n[10];
8 FILE *fp;
9
See Also
fopen(), fread()
Synopsis
#include <stdio.h>
Description
These functions are just like ftell() and fseek(), except instead of counting in bytes, they use an
opaque data structure to hold positional information about the file. (Opaque, in this case, means you’re
not supposed to know what the data type is made up of.)
On virtually every system (and certainly every system that I know of), people don’t use these functions,
using ftell() and fseek() instead. These functions exist just in case your system can’t remember file
positions as a simple byte offset.
Since the pos variable is opaque, you have to assign to it using the fgetpos() call itself. Then you save
the value for later and use it to reset the position using fsetpos().
Return Value
Both functions return zero on success, and -1 on error.
524 Chapter 61. <stdio.h> Standard I/O Library
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char s[100];
6 fpos_t pos;
7 FILE *fp;
8
9 fp = fopen("spoon.txt", "r");
10
24 fclose(fp);
25 }
See Also
fseek(), ftell(), rewind()
Synopsis
#include <stdio.h>
Description
When doing reads and writes to a file, the OS keeps track of where you are in the file using a counter
generically known as the file pointer. You can reposition the file pointer to a different point in the file
using the fseek() call. Think of it as a way to randomly access you file.
The first argument is the file in question, obviously. offset argument is the position that you want to
seek to, and whence is what that offset is relative to.
Of course, you probably like to think of the offset as being from the beginning of the file. I mean, “Seek
to position 3490, that should be 3490 bytes from the beginning of the file.” Well, it can be, but it doesn’t
have to be. Imagine the power you’re wielding here. Try to command your enthusiasm.
61.22. fseek(), rewind() 525
whence Description
SEEK_SET offset is relative to the beginning of the file. This is probably what you had in mind
anyway, and is the most commonly used value for whence.
SEEK_CUR offset is relative to the current file pointer position. So, in effect, you can say,
“Move to my current position plus 30 bytes,” or, “move to my current position minus
20 bytes.”
SEEK_END offset is relative to the end of the file. Just like SEEK_SET except from the other end
of the file. Be sure to use negative values for offset if you want to back up from the
end of the file, instead of going past the end into oblivion.
Speaking of seeking off the end of the file, can you do it? Sure thing. In fact, you can seek way off the
end and then write a character; the file will be expanded to a size big enough to hold a bunch of zeros way
out to that character.
Now that the complicated function is out of the way, what’s this rewind() that I briefly mentioned? It
repositions the file pointer at the beginning of the file:
fseek(fp, 0, SEEK_SET); // same as rewind()
rewind(fp); // same as fseek(fp, 0, SEEK_SET)
Return Value
For fseek(), on success zero is returned; -1 is returned on failure.
The call to rewind() never fails.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 FILE *fp;
6
7 fp = fopen("spoon.txt", "r");
8
12 fseek(fp, -31, SEEK_CUR); // seek backward 30 bytes from the current pos
13 printf("31 back: %c\n", fgetc(fp));
14
15 fseek(fp, -12, SEEK_END); // seek to the 10th byte before the end of file
16 printf("12 from end: %c\n", fgetc(fp));
17
22 fclose(fp);
23 }
See Also
ftell(), fgetpos(), fsetpos()
526 Chapter 61. <stdio.h> Standard I/O Library
61.23 ftell()
Tells you where a particular file is about to read from or write to
Synopsis
#include <stdio.h>
Description
This function is the opposite of fseek(). It tells you where in the file the next file operation will occur
relative to the beginning of the file.
It’s useful if you want to remember where you are in the file, fseek() somewhere else, and then come
back later. You can take the return value from ftell() and feed it back into fseek() (with whence
parameter set to SEEK_SET) when you want to return to your previous position.
Return Value
Returns the current offset in the file, or -1 on error.
Example
1 #include <stdio.h>
2
3 int main(void)
4 {
5 char c[6];
6 FILE *fp;
7
8 fp = fopen("spoon.txt", "r");
9
10 long pos;
11
31 fclose(fp);
32 }
See Also
fseek(), rewind(), fgetpos(), fsetpos()
Synopsis
#include <stdio.h>
Description
Each FILE* that you use to read and write data from and to a file contains flags that the system sets when
certain events occur. If you get an error, it sets the error flag; if you reach the end of the file during a read,
it sets the EOF flag. Pretty simple really.
The functions feof() and ferror() give you a simple way to test these flags: they’ll return non-zero
(true) if they’re set.
Once the flags are set for a particular stream, they stay that way until you call clearerr() to clear them.
Return Value
feof() and ferror() return non-zero (true) if the file has reached EOF or there has been an error, re-
spectively.
Example
Read binary data, checking for EOF or error:
1 #include <stdio.h>
2
3 int main(void)
4 {
5 int a;
6 FILE *fp;
7
8 fp = fopen("numbers.dat", "r");
9
16 if (feof(fp))
17 printf("End of file was reached.\n");
18
19 if (ferror(fp))
20 printf("An error occurred.\n");
21
22 fclose(fp);
23 }
See Also
fopen(), fread()
61.25 perror()
Print the last error message to stderr
Synopsis
#include <stdio.h>
#include <errno.h> // only if you want to directly use the "errno" var
Description
Many functions, when they encounter an error condition for whatever reason, will set a global variable
called errno (in <errno.h>) for you. errno is just an interger representing a unique error.
But to you, the user, some number isn’t generally very useful. For this reason, you can call perror()
after an error occurs to print what error has actually happened in a nice human-readable string.
And to help you along, you can pass a parameter, s, that will be prepended to the error string for you.
One more clever trick you can do is check the value of the errno (you have to include errno.h to see it)
for specific errors and have your code do different things. Perhaps you want to ignore certain errors but
not others, for instance.
The standard only defines three values for errno, but your system undoubtedly defines more. The three
that are defined are:
errno Description
EDOM Math operation outside domain.
EILSEQ Invalid sequence in multibyte to wide character encoding.
ERANGE Result of operation doesn’t fit in specified type.
The catch is that different systems define different values for errno, so it’s not very portable beyond the
above 3. The good news is that at least the values are largely portable between Unix-like systems, at least.
Return Value
Returns nothing at all! Sorry!
61.25. perror() 529
Example
fseek() returns -1 on error, and sets errno, so let’s use it. Seeking on stdin makes no sense, so it
should generate an error:
1 #include <stdio.h>
2 #include <errno.h> // must include this to see "errno" in this example
3
4 int main(void)
5 {
6 if (fseek(stdin, 10L, SEEK_SET) < 0)
7 perror("fseek");
8
17 if (errno == EBADF) {
18 perror("fseek again, EBADF");
19 } else {
20 perror("fseek again");
21 }
22 }
23 }
See Also
feof(), ferror(), strerror()
530 Chapter 61. <stdio.h> Standard I/O Library
Chapter 62
Some of the following functions have variants that handle different types: atoi(), strtod(), strtol(),
abs(), and div(). Only a single one is listed here for brevity.
Function Description
_Exit() Exit the currently-running program and don’t look back
abort() Abruptly end program execution
abs() Compute the absolute value of an integer
aligned_alloc() Allocate specifically-aligned memory
at_quick_exit() Set up handlers to run when the program quickly exits
atexit() Set up handlers to run when the program exits
atof() Convert a string to a floating point value
atoi() Convert an integer in a string into a integer type
bsearch() Binary Search (maybe) an array of objects
calloc() Allocate and clear memory for arbitrary use
div() Compute the quotient and remainder of two numbers
exit() Exit the currently-running program
free() Free a memory region
getenv() Get the value of an environment variable
malloc() Allocate memory for arbitrary use
mblen() Return the number of bytes in a multibyte character
mbstowcs() Convert a multibyte string to a wide character string
mbtowc() Convert a multibyte character to a wide character
qsort() Quicksort (maybe) some data
quick_exit() Exit the currently-running program quickly
rand() Return a pseudorandom number
realloc() Resize a previously allocated stretch of memory
srand() Seed the built-in pseudorandom number generator
strtod() Convert a string to a floating point number
strtol() Convert a string to an integer
system() Run an external program
wcstombs() Convert a wide character string to a multibyte string
wctomb() Convert a wide character to a multibyte character
The <stdlib.h> header has all kinds of—dare I say—miscellaneous functions bundled into it. This
functionality includes:
• Conversions from numbers to strings
• Conversions from strings to numbers
531
532 Chapter 62. <stdlib.h> Standard Library Functions
Type Description
size_t Returned from sizeof and used elsewhere
wchar_t For wide character operations
div_t For the div() function
ldiv_t For the ldiv() function
lldiv_t for the lldiv() function
Type Description
NULL Our good pointer friend
EXIT_SUCCESS Good exit status when things go well
EXIT_FAILURE Good exit status when things go poorly
RAND_MAX The maximum value that can be returned by the
rand() function
MB_CUR_MAX Maximum number of bytes in a multibyte
character in the current locale
And there you have it. Just a lot of fun, useful functions in here. Let’s check ’em out!
62.2 atof()
Convert a string to a floating point value
Synopsis
#include <stdlib.h>
Description
This stood for “ASCII-To-Floating” back in the day1 , but no one would dare to use such coarse language
now.
But the gist is the same: we’re going to convert a string with numbers and (optionally) a decimal point into
a floating point value. Leading whitespace is ignored, and translation stops at the first invalid character.
1
http://man.cat-v.org/unix-1st/3/atof
62.3. atoi(), atol(), atoll() 533
Return Value
Returns the string converted to a double.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 double x = atof("3.141593");
7
See Also
atoi(), strtod()
Synopsis
#include <stdlib.h>
Description
Back in the day, atoi() stood for “ASCII-To_Integer”2 but now the spec makes no mention of that.
These functions take a string with a number in them and convert it to an integer of the specified return
type. Leading whitespace is ignored. Translation stops at the first invalid character.
If the result doesn’t fit in the return type, behavior is undefined.
It generally works as if you’d called strtol() family of functions:
2
http://man.cat-v.org/unix-1st/3/atoi
534 Chapter 62. <stdlib.h> Standard Library Functions
Again, the strtol() functions are generally better, so I recommend them instead of these.
Return Value
Returns an integer result corresponding to the return type.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 int x = atoi("3490");
7
See Also
atof(), strtol()
Synopsis
#include <stdlib.h>
Description
These are some neat functions that convert strings to floating point numbers (or even NaN or Infinity) and
provide some error checking, besides.
Firstly, leading whitespace is skipped.
Then the functions attempt to convert characters into the floating point result. Finally, when an invalid
character (or NUL character) is reached, they set endptr to point to the invalid character.
Set endptr to NULL if you don’t care about where the first invalid character is.
62.4. strtod(), strtof(), strtold() 535
If you didn’t set endptr to NULL, it will point to a NUL character if the translation didn’t find any bad
characters. That is:
if (*endptr == '\0') {
printf("What a perfectly-formed number!\n");
} else {
printf("I found badness in your number: \"%s\"\n", endptr);
}
But guess what! You can also translate strings into special values, like NaN and Infinity!
If nptr points to a string containing INF or INFINITY (upper or lowercase), the value for Infinity will be
returned.
If nptr points to a string containing NAN, then (a quiet, non-signalling) NaN will be returned. You can tag
the NAN with a sequence of characters from the set 0-9, a-z, A-Z, and _ by enclosing them in parens:
NAN(foobar_3490)
What your compiler does with this is implementation-defined, but it can be used to specify different kinds
of NaN.
You can also specify a number in hexadecimal with a power-of-two exponent (2𝑥 ) if you lead with 0x (or
0X). For the exponent, use a p followed by a base 10 exponent. (You can’t use e because that’s a valid hex
digit!)
Example:
0xabc.123p15
Return Value
Returns the converted number. If there was no number, returns 0. endptr is set to point to the first invalid
character, or the NUL terminator if all characters were consumed.
If there’s an overflow, HUGE_VAL, HUGE_VALF, or HUGE_VALL is returned, signed like the input, and errno
is set to ERANGE.
If there’s an underflow, it returns the smallest number closest to zero with the input sign. errno may be
set to ERANGE.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 char *inp = " 123.4567beej";
7 char *badchar;
8
19 if (*badchar == '\0')
20 printf("No bad chars: %f\n", val);
21 else
22 printf("Found bad chars: %f, %s\n", val, badchar);
23 }
Output:
Converted string to 123.456700
Encountered bad characters: beej
Ignoring bad chars: 987.654321
No bad chars: 11.223300
See Also
atof(), strtol()
Synopsis
#include <stdlib.h>
Description
These convert a string to an integer like atoi(), but they have a few more bells and whistles.
Most notable, they can tell you where conversion started going wrong, i.e. where invalid characters, if
any, appear. Leading spaces are ignored. A + or - sign may precede the number.
The basic idea is that if things go well, these functions will return the integer values contained in the
strings. And if you pass in the char** typed endptr, it’ll set it to point at the NUL at the end of the
string.
If things don’t go well, they’ll set endptr to point at the first character where things have gone awry. That
is, if you’re converting a value 103z2! in base 10, they’ll send endptr to point at the z because that’s
the first non-numeric character.
You can pass in NULL for endptr if you don’t care to do any of that kind of error checking.
62.5. strtol(), strtoll(), strtoul(), strtoull() 537
Wait—did I just say we could set the number base for the conversion? Yes! Yes, I did. Now number
bases3 are out of scope for this document, but certainly some of the more well-known are binary (base 2),
octal (base 8), decimal (base 10), and hexadecimal (base 16).
You can specify the number base for the conversion as the third parameter. Bases from 2 to 36 are sup-
ported, with case-insensitive digits running from 0 to Z.
If you specify a base of 0, the function will make an effort to determine it. It’ll default to base 10 except
for a couple cases:
• If the number has a leading 0, it will be octal (base 8)
• If the number has a leading 0x or 0X, it will be hex (base 16)
The locale might affect the behavior of these functions.
Return Value
Returns the converted value.
endptr, if not NULL is set to the first invalid character, or to the beginning of the string if no conversion
was performed, or to the string terminal NUL if all characters were valid.
If there’s overflow, one of these values will be returned: LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX,
ULONG_MAX, ULLONG_MAX. And errno is set to ERANGE.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 // All output in decimal (base 10)
7
17 char *badchar;
18 long int x = strtol(" 1234beej", &badchar, 0);
19
Output:
123
123
42
83
291
83
291
3
https://en.wikipedia.org/wiki/Radix
538 Chapter 62. <stdlib.h> Standard Library Functions
Value is 1234
Bad chars at "beej"
See Also
atoi(), strtod(), setlocale(), strtoimax(), strtoumax()
62.6 rand()
Return a pseudorandom number
Synopsis
#include <stdlib.h>
int rand(void);
Description
This gives us back a pseudorandom number in the range 0 to RAND_MAX, inclusive. (RAND_MAX will be at
least 32767.)
If you want to force this to a certain range, the classic way to do this is to force it with the modulo operator
%, although this introduces biases4 if RAND_MAX+1 is not a multiple of the number you’re modding by.
Dealing with this is out of scope for this guide.
If you want to to make a floating point number between 0 and 1 inclusive, you can divide the result by
RAND_MAX. Or RAND_MAX+1 if you don’t want to include 1. But of course, there are out-of-scope problems
with this, as well5 .
In short, rand() is a great way to get potentially poor random numbers with ease. Probably good enough
for the game you’re writing.
The spec elaborates:
There are no guarantees as to the quality of the random sequence produced and some imple-
mentations are known to produce sequences with distressingly non-random low-order bits.
Applications with particular requirements should use a generator that is known to be suffi-
cient for their needs.
Your system probably has a good random number generator on it if you need a stronger source. Linux
users have getrandom(), for example, and Windows has CryptGenRandom().
For other more demanding random number work, you might find a library like the GNU Scientific Library6
of use.
With most implementations, the numbers produced by rand() will be the same from run to run. To get
around this, you need to start it off in a different place by passing a seed into the random number generator.
You can do this with srand().
Return Value
Returns a random number in the range 0 to RAND_MAX, inclusive.
4
https://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-
generator
5
https://mumble.net/~campbell/2014/04/28/uniform-random-float
6
https://www.gnu.org/software/gsl/doc/html/rng.html
62.7. srand() 539
Example
Note that all of these examples don’t produce perfectly uniform distributions. But good enough for the
untrained eye, and really common in general use when mediocre random number quality is acceptable.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 printf("RAND_MAX = %d\n", RAND_MAX);
7
Output on my system:
RAND_MAX = 2147483647
0 to 9: 3
10 to 44: 21
0 to 0.99999: 0.783099
10.5 to 15.7: 14.651888
5 int main(void)
6 {
7 // time(NULL) very likely returns the number of seconds since
8 // January 1, 1970:
9
10 srand(time(NULL));
11
See Also
srand()
62.7 srand()
Seed the built-in pseudorandom number generator
Synopsis
#include <stdlib.h>
Description
The dirty little secret of pseudorandom number generation is that they’re completely deterministic. There’s
nothing random about them. They just look random.
If you use rand() and run your program several times, you might notice something fishy: they produce
the same random numbers over and over again.
To mix it up, we need to give the pseudorandom number generator a new “starting point”, if you will. We
call that the seed. It’s just a number, but it is used as the basic for subsequent number generation. Give
a different seed, and you’ll get a different sequence of random numbers. Give the same seed, and you’ll
get the same sequence of random numbers corresponding to it7 .
So if you call srand(3490) before you start generating numbers with rand(), you’ll get the same se-
quence every time. srand(37) would also give you the same sequence every time, but it would be a
different sequence than the one you got with srand(3490).
But if you can’t hardcode the seed (because that would give you the same sequence every time), how are
you supposed to do this?
It’s really common to use the number of seconds since January 1, 1970 (this date is known as the Unix
epoch8 ) to seed the generator. This sounds pretty arbitrary except for the fact that it’s exactly the value
most implementations return from the library call time(NULL)9 .
We’ll do that in the example.
If you don’t call srand(), it’s as if you called srand(1).
Return Value
Returns nothing!
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <time.h> // for the time() call
4
5 int main(void)
6 {
7 srand(time(NULL));
8
Output:
4
20
22
14
9
7
Minecraft enthusiasts might recall that when generating a new world, they were given the option to enter a random number seed.
That single value is used to generate that entire random world. And if your friend starts a world with the same seed you did, they’ll
get the same world you did.
8
https://en.wikipedia.org/wiki/Unix_time
9
The C spec doesn’t say exactly what time(NULL) will return, but the POSIX spec does! And virtually everyone returns exactly
that: the number of seconds since epoch.
62.8. aligned_alloc() 541
19
0
31
31
24
See Also
rand(), time()
62.8 aligned_alloc()
Allocate specifically-aligned memory
Synopsis
#include <stdlib.h>
Description
Maybe you wanted malloc() or calloc() instead of this. But if you’re sure you don’t, read on!
Normally you don’t have to think about this, since malloc() and realloc() both provide memory
regions that are suitably aligned10 for use with any data type.
But if you need a more specific alignment, you can specify it with this function.
When you’re done using the memory region, be sure to free it with a call to free().
Don’t pass in 0 for the size. It probably won’t do anything you want.
In case you’re wondering, all dynamically-allocated memory is automatically freed by the system when
the program ends. That said, it’s considered to be Good Form to explicitly free() everything you allocate.
This way other programmers don’t think you were being sloppy.
Return Value
Returns a pointer to the newly-allocated memory, aligned as specified. Returns NULL if something goes
wrong.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4
5 int main(void)
6 {
7 int *p = aligned_alloc(256, 10 * sizeof(int));
8
9 // Just for fun, let's convert to intptr_t and mod with 256
10 // to make sure we're actually aligned on a 256-byte boundary.
11 //
10
https://en.wikipedia.org/wiki/Data_structure_alignment
542 Chapter 62. <stdlib.h> Standard Library Functions
15 intptr_t ip = (intptr_t)p;
16
17 printf("%ld\n", ip % 256); // 0!
18
19 // Free it up
20 free(p);
21 }
See Also
malloc(), calloc(), free()
Synopsis
#include <stdlib.h>
Description
Both of these functions allocate memory for general-purpose use. It will be aligned such that it’s useable
for storing any data type.
malloc() allocates exactly the specified number of bytes of memory in a contiguous block. The memory
might be full of garbage data. (You can clear it with memset(), if you wish.)
calloc() is different in that it allocates space for nmemb objects of size bytes each. (You can do the
same with malloc(), but you have to do the multiplication yourself.)
So if you’re planning to zero the memory anyway, calloc() is probably the way to go. If you’re not,
you can avoid that overhead by calling malloc().
When you’re done using the memory region, free it with a call to free().
Don’t pass in 0 for the size. It probably won’t do anything you want.
In case you’re wondering, all dynamically-allocated memory is automatically freed by the system when
the program ends. That said, it’s considered to be Good Form to explicitly free() everything you allocate.
This way other programmers don’t think you were being sloppy.
Return Value
Both functions return a pointer to the shiny, newly-allocated memory. Or NULL if something’s gone awry.
62.10. free() 543
Example
Comparison of malloc() and calloc() for allocating 5 ints:
1 #include <stdlib.h>
2
3 int main(void)
4 {
5 // Allocate space for 5 ints
6 int *p = malloc(5 * sizeof(int));
7
8 p[0] = 12;
9 p[1] = 30;
10
15 q[0] = 12;
16 q[1] = 30;
17
18 // All done
19 free(p);
20 free(q);
21 }
See Also
aligned_alloc(), free()
62.10 free()
Free a memory region
Synopsis
#include <stdlib.h>
Description
You know that pointer you got back from malloc(), calloc(), or aligned_alloc()? You pass that
pointer to free() to free the memory associated with it.
If you don’t do this, the memory will stay allocated FOREVER AND EVER! (Well, until your program
exits, anyway.)
Fun fact: free(NULL) does nothing. You can safely call that. Sometimes it’s convenient.
Don’t free() a pointer that’s already been free()d. Don’t free() a pointer that you didn’t get back
from one of the allocation functions. It would be Bad11 .
Return Value
Returns nothing!
11
“Try to imagine all life as you know it stopping instantaneously and every molecule in your body exploding at the speed of
light.” —Egon Spengler
544 Chapter 62. <stdlib.h> Standard Library Functions
Example
1 #include <stdlib.h>
2
3 int main(void)
4 {
5 // Allocate space for 5 ints
6 int *p = malloc(5 * sizeof(int));
7
8 p[0] = 12;
9 p[1] = 30;
10
See Also
malloc(), calloc(), aligned_alloc()
62.11 realloc()
Resize a previously allocated stretch of memory
Synopsis
#include <stdlib.h>
Description
This takes a pointer to some memory previously allocated with malloc() or calloc() and resizes it to
the new size.
If the new size is smaller than the old size, any data larger than the new size is discarded.
If the new size is larger than the old size, the new larger part is uninitialized. (You can clear it with
memset().)
Important note: the memory might move! If you resize, the system might need to relocate the memory
to a larger continguous chunk. If this happens, realloc() will copy the old data to the new location for
you.
Because of this, it’s important to save the returned value to your pointer to update it to the new location if
things move. (Also, be sure to error-check so that you don’t overwrite your old pointer with NULL, leaking
the memory.)
You can also relloc() memory allocated with aligned_alloc(), but it will potentially lose its align-
ment if the block is moved.
Return Value
Returns a pointer to the resized memory region. This might be equivalent to the ptr passed in, or it might
be some other location.
62.12. abort() 545
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 // Allocate space for 5 ints
7 int *p = malloc(5 * sizeof(int));
8
9 p[0] = 12;
10 p[1] = 30;
11
15 if (new_p == NULL) {
16 printf("Error reallocing\n");
17 } else {
18 p = new_p; // It's good; let's keep it
19 p[7] = 99;
20 }
21
22 // All done
23 free(p);
24 }
See Also
malloc(), calloc()
62.12 abort()
Abruptly end program execution
Synopsis
#include <stdlib.h>
Description
This ends program execution abnormally and immediately. Use this in rare, unexpected circumstances.
Open streams might not be flushed. Temporary files created might not be removed. Exit handlers are not
called.
A non-zero exit status is returned to the environment.
On some systems, abort() might dump core12 , but this is outside the scope of the spec.
You can cause the equivalent of an abort() by calling raise(SIGABRT), but I don’t know why you’d
do that.
12
https://en.wikipedia.org/wiki/Core_dump
546 Chapter 62. <stdlib.h> Standard Library Functions
The only portable way to stop an abort() call midway is to use signal() to catch SIGABRT and then
exit() in the signal handler.
Return Value
This function never returns.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 int bad_thing = 1;
7
8 if (bad_thing) {
9 printf("This should never have happened!\n");
10 fflush(stdout); // Make sure the message goes out
11 abort();
12 }
13 }
See Also
signal()
Synopsis
#include <stdlib.h>
Description
When the program does a normal exit with exit() or returns from main(), it looks for previously-
registered handlers to call on the way out. These handlers are registered with the atexit() call.
Think of it like, “Hey, when you’re about to exit, do these extra things.”
For the quick_exit() call, you can use the at_quick_exit() function to register handlers for that13 .
There’s no crossover in handlers from exit() to quick_exit(), i.e. for a call to one, none of the other’s
handlers will fire.
13
quick_exit() differs from exit() in that open files might not be flushed and temporary files might not be removed.
62.13. atexit(), at_quick_exit() 547
You can register multiple handlers to fire—at least 32 handlers are supported by both exit() and
quick_exit().
The argument func to the functions looks a little weird—it’s a pointer to a function to call. Basically just
put the function name to call in there (without parentheses after). See the example, below.
If you call atexit() from inside your atexit() handler (or equivalent in your at_quick_exit() han-
dler), it’s unspecified if it will get called. So get them all registered before you exit.
When exiting, the functions will be called in the reverse order they were registered.
Return Value
These functions return 0 on success, or nonzero on failure.
Example
atexit():
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 void exit_handler_1(void)
5 {
6 printf("Exit handler 1 called!\n");
7 }
8
9 void exit_handler_2(void)
10 {
11 printf("Exit handler 2 called!\n");
12 }
13
14 int main(void)
15 {
16 atexit(exit_handler_1);
17 atexit(exit_handler_2);
18
19 exit(0);
20 }
4 void exit_handler_1(void)
5 {
6 printf("Exit handler 1 called!\n");
7 }
8
9 void exit_handler_2(void)
10 {
11 printf("Exit handler 2 called!\n");
12 }
13
14 int main(void)
15 {
548 Chapter 62. <stdlib.h> Standard Library Functions
16 at_quick_exit(exit_handler_1);
17 at_quick_exit(exit_handler_2);
18
19 quick_exit(0);
20 }
See Also
exit(), quick_exit()
Synopsis
#include <stdlib.h>
Description
All these functions cause the program to exit, with various levels of cleanup performed.
exit() does the most cleanup and is the most normal exit.
Calling either of exit() or quick_exit() causes their respective atexit() or at_quick_exit() han-
dlers to be called in the reverse order in which they were registered.
exit() will flush all streams and delete all temporary files.
Status Description
EXIT_SUCCESS Typically returned when good things happen
0 Same as EXIT_SUCCESS
EXIT_FAILURE Oh noes! Definitely failure!
Any positive value Generally indicates another failure of some kind
Return Value
None of these functions ever return.
62.15. getenv() 549
Example
1 #include <stdlib.h>
2
3 int main(void)
4 {
5 int contrived_exit_type = 1;
6
7 switch(contrived_exit_type) {
8 case 1:
9 exit(EXIT_SUCCESS);
10
11 case 2:
12 // Not supported in OS X
13 quick_exit(EXIT_SUCCESS);
14
15 case 3:
16 _Exit(2);
17 }
18 }
See Also
atexit(), at_quick_exit()
62.15 getenv()
Get the value of an environment variable
Synopsis
#include <stdlib.h>
Description
The environment often provides variables that are set before the program run that you can access at run-
time.
Of course the exact details are system dependent, but these variables are key/value pairs, and you can get
the value by passing the key to getenv() as the name parameter.
You’re not allowed to overwrite the string that’s returned.
This is pretty limited in the standard, but your OS often provides better functionality. See the Environment
Variables section for more details.
Return Value
Returns a pointer to the environment variable value, or NULL if the variable doesn’t exist.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
550 Chapter 62. <stdlib.h> Standard Library Functions
4 int main(void)
5 {
6 printf("PATH is %s\n", getenv("PATH"));
7 }
62.16 system()
Run an external program
Synopsis
#include <stdlib.h>
Description
This will run an external program and then return to the caller.
The manner in which it runs the program is system-defined, but typically you can pass something to it just
like you’d run on the command line, searching the PATH, etc.
Not all systems have this capability, but you can test for it by passing NULL to system() and seeing if it
returns 0 (no command processor is available) or non-zero (a command processor is available! Yay!)
If you’re getting user input and passing it to the system() call, be extremely careful to escape all special
shell characters (everything that’s not alphanumeric) with a backslash to keep a villain from running
something you don’t want them to.
Return Value
If NULL is passed, returns nonzero if a command processor is available (i.e. system() will work at all).
Otherwise returns an implementation-defined value.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 printf("Here's a directory listing:\n\n");
7
10 printf("\nAll done!\n");
11 }
Output:
62.17. bsearch() 551
total 92
drwxr-xr-x 3 beej beej 4096 Oct 14 21:38 bin
drwxr-xr-x 2 beej beej 4096 Dec 20 20:07 examples
-rwxr-xr-x 1 beej beej 16656 Feb 23 21:49 foo
-rw-rw-rw- 1 beej beej 155 Feb 23 21:49 foo.c
-rw-r--r-- 1 beej beej 1350 Jan 27 22:11 Makefile
-rw-r--r-- 1 beej beej 4644 Jan 18 09:12 README.md
drwxr-xr-x 3 beej beej 4096 Feb 23 20:21 src
drwxr-xr-x 6 beej beej 4096 Feb 21 20:24 stage
drwxr-xr-x 2 beej beej 4096 Sep 27 20:54 translations
drwxr-xr-x 2 beej beej 4096 Sep 27 20:54 website
All done!
62.17 bsearch()
Binary Search (maybe) an array of objects
Synopsis
#include <stdlib.h>
Description
This crazy-looking function searches an array for a value.
It probably is a binary search or some fast, efficient search. But the spec doesn’t really say.
However, the array must be sorted! So binary search seems likely.
• key is a pointer to the value to find.
• base is a pointer to the start of the array—the array must be sorted!
• nmemb is the number of elements in the array.
• size is the sizeof each element in the array.
• compar is a pointer to a function that will compare the key against other values.
The comparison function takes the key as the first argument and the value to compare against as the second.
It should return a negative number if the key is less than the value, 0 if the key equals the value, and a
positive number if the key is greater than the value.
This is commonly computed by taking the difference between the key and the value to be compared. If
subtraction is supported.
The return value from the strcmp() function can be used for comparing strings.
Again, the array must be sorted according to the order of the comparison function before running
bsearch(). Luckily for you, you can just call qsort() with the same comparison function to get this
done.
It’s a general-purpose function—it’ll search any type of array for anything. The catch is you have to write
the comparison function.
And that’s not as scary as it looks. Jump down to the example
552 Chapter 62. <stdlib.h> Standard Library Functions
Return Value
The function returns a pointer to the found value, or NULL if it can’t be found.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
8 return *k - *v;
9 }
10
11 int main(void)
12 {
13 int a[9] = {2, 6, 9, 12, 13, 18, 20, 32, 47};
14
Output:
Found 12
Didn't find 30
Found 32
See Also
strcmp(), qsort()
62.18 qsort()
Quicksort (maybe) some data
Synopsis
#include <stdlib.h>
Description
This function will quicksort (or some other sort, probably speedy) an array of data in-place14 .
Like bsearch(), it’s data-agnostic. Any data for which you can define a relative ordering can be sorted,
whether ints, structs, or anything else.
Also like bsearch(), you have to give a comparison function to do the actual compare.
• base is a pointer to the start of the array to be sorted.
• nmemb is the number of elements in the array.
• size is the sizeof each element.
• compar is a pointer to the comparison function.
The comparison function takes pointers to two elements of the array as arguments and compares them. It
should return a negative number if the first argument is less than the second, 0 if they are equal, and a
positive number if the first argument is greater than the second.
This is commonly computed by taking the difference between the first argument and the second. If sub-
traction is supported.
The return value from the strcmp() function can provide sort order for strings.
If you have to sort a struct, just subtract the specific field you want to sort by.
This comparison function can be used by bsearch() to do searches after the list is sorted.
To reverse the sort, subtract the second argument from the first, i.e. negate the return value from compar().
Return Value
Returns nothing!
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
13 int main(void)
14 {
15 int a[9] = {14, 2, 3, 17, 10, 8, 6, 1, 13};
16
26 putchar('\n');
14
“In-place” meaning that the original array will hold the results; no new array is allocated.
554 Chapter 62. <stdlib.h> Standard Library Functions
27
Output:
1 2 3 6 8 10 13 14 17
Found 17!
See Also
strcmp(), bsearch()
Synopsis
#include <stdlib.h>
Description
Compute the absolute value of j. If you don’t remember, that’s how far from zero j is.
In other words, if j is negative, return it as a positive. If it’s positive, return it as a positive. Always be
positive. Enjoy life.
If the result cannot be represented, the behavior is undefined. Be especially aware of the upper half of
unsigned numbers.
Return Value
Returns the absolute value of j, |𝑗|.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 printf("|-2| = %d\n", abs(-2));
7 printf("|4| = %d\n", abs(4));
8 }
Output:
62.20. div(), ldiv(), lldiv() 555
|-2| = 2
|4| = 4
See Also
fabs()
Synopsis
#include <stdlib.h>
Description
These functions get you the quotient and remainder of a pair of numbers in one go.
They return a structure that has two fields, quot, and rem, the types of which match types of numer and
denom. Note how each function returns a different variant of div_t.
typedef struct {
long int quot, rem;
} ldiv_t;
typedef struct {
long long int quot, rem;
} lldiv_t;
The Rationale then goes on to spell out what the signs of the quotient and remainder will be given the
signs of a numerator and denominator when using the div() functions:
Return Value
A div_t, ldiv_t, or lldiv_t structure with the quot and rem fields loaded with the quotient and re-
mainder of the operation of numer/denom.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void)
5 {
6 div_t d = div(64, -7);
7
Output:
64 / -7 = -9
64 % -7 = 1
See Also
fmod(), remainder()
62.21 mblen()
Return the number of bytes in a multibyte character
Synopsis
#include <stdlib.h>
Description
If you have a multibyte character in a string, this will tell you how many bytes long it is.
n is the maximum number of bytes mblen() will scan before giving up.
If s is a NULL pointer, tests if this encoding has state dependency, as noted in the return value, below. It
also resets the state, if there is one.
The behavior of this function is influenced by the locale.
62.22. mbtowc() 557
Return Value
Returns the number of bytes used to encode this character, or -1 if there is no valid multibyte character in
the next n bytes.
Or, if s is NULL, returns true if this encoding has state dependency.
Example
For the example, I used my extended character set to put Unicode characters in the source. If this doesn’t
work for you, use the \uXXXX escape.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <locale.h>
4
5 int main(void)
6 {
7 setlocale(LC_ALL, "");
8
Output (in my case, the encoding is UTF-8, but your mileage may vary):
State dependency: 0
Bytes for €: 3
Bytes for é: 2
Bytes for &: 1
See Also
mbtowc(), mbstowcs()), setlocale()
62.22 mbtowc()
Convert a multibyte character to a wide character
Synopsis
#include <stdlib.h>
Description
If you have a multibyte character, this function will convert it to a wide character and stored at the address
pointed to by pwc. Up to n bytes of the multibyte character will be analyzed.
If pwc is NULL, the resulting character will not be stored. (Useful for just getting the return value.)
If s is a NULL pointer, tests if this encoding has state dependency, as noted in the return value, below. It
also resets the state, if there is one.
The behavior of this function is influenced by the locale.
558 Chapter 62. <stdlib.h> Standard Library Functions
Return Value
Returns the number of bytes used in the encoded wide character, or -1 if there is no valid multibyte
character in the next n bytes.
Returns 0 if s points to the NUL character.
Or, if s is NULL, returns true if this encoding has state dependency.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <locale.h>
4 #include <wchar.h>
5
6 int main(void)
7 {
8 setlocale(LC_ALL, "");
9
12 wchar_t wc;
13 int bytes;
14
Output on my system:
State dependency: 0
L'€' takes 3 bytes as multibyte char '€'
See Also
mblen(), mbstowcs(), wcstombs(), setlocale()
62.23 wctomb()
Convert a wide character to a multibyte character
Synopsis
#include <stdlib.h>
Description
If you have your hands on a wide character, you can use this to make it multibyte.
The wide character wc is stored as a multibyte character in the string pointed to by s. The buffer s points
to should be at least MB_CUR_MAX characters long. Note that MB_CUR_MAX changes with locale.
If wc is a NUL wide character, a NUL is stored in s after the bytes needed to reset the shift state (if any).
62.24. mbstowcs() 559
If s is a NULL pointer, tests if this encoding has state dependency, as noted in the return value, below. It
also resets the state, if there is one.
The behavior of this function is influenced by the locale.
Return Value
Returns the number of bytes used in the encoded multibyte character, or -1 if wc does not correspond to
any valid multibyte character.
Or, if s is NULL, returns true if this encoding has state dependency.
Example
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <locale.h>
4 #include <wchar.h>
5
6 int main(void)
7 {
8 setlocale(LC_ALL, "");
9
12 int bytes;
13 char mb[MB_CUR_MAX + 1];
14
Output on my system:
State dependency: 0
L'€' takes 3 bytes as multibyte char '€'
See Also
mbtowc(), mbstowcs(), wcstombs(), setlocale()
62.24 mbstowcs()
Convert a multibyte string to a wide character string
Synopsis
#include <stdlib.h>
Description
If you have a multibyte string (AKA a regular string), you can convert it wto a wide character string with
this function.
560 Chapter 62. <stdlib.h> Standard Library Functions
At most n wide characters are written to the destination pwcs from the source s.
A NUL character is stored as a wide NUL character.
Non-portable POSIX extension: if you’re using a POSIX-complaint library, this function allows pwcs
to be NULL if you’re only interested in the return value. Most notably, this will give you the number of
characters in a multibyte string (as opposed to strlen() which counts the bytes.)
Return Value
Returns the number of wide characters written to the destination pwcs.
If an invalid multibyte character was found, returns (size_t)(-1).
If the return value is n, it means the result was not NUL-terminated.
Example
This source uses an extended character set. If your compiler doesn’t support it, you’ll have to replace
them with \u escapes.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <locale.h>
4 #include <string.h>
5
6 int main(void)
7 {
8 setlocale(LC_ALL, "");
9
10 wchar_t wcs[128];
11 char *s = "€200 for this spoon?"; // 20 characters
12
27 s = "§¶°±π€•"; // 7 characters
28
Byte count : 22
See Also
mblen(), mbtowc(), wcstombs(), setlocale()
62.25 wcstombs()
Convert a wide character string to a multibyte string
Synopsis
#include <stdlib.h>
Description
If you have a wide character string and you want it as multibyte string, this is the function for you!
It’ll take the wide characters pointed to by pwcs and convert them to multibyte characters stored in s. No
more than n bytes will be written to s.
Non-portable POSIX extension: if you’re using a POSIX-complaint library, this function allows s to be
NULL if you’re only interested in the return value. Most notably, this will give you the number of bytes
needed to encode the wide characters in a multibyte string.
Return Value
Returns the number of bytes written to s, or (size_t)(-1) if one of the characters can’t be encoded into
a multibyte string.
If the return value is n, it means the result was not NUL-terminated.
Example
This source uses an extended character set. If your compiler doesn’t support it, you’ll have to replace
them with \u escapes.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <locale.h>
4 #include <string.h>
5
6 int main(void)
7 {
8 setlocale(LC_ALL, "");
9
10 char mbs[128];
11 wchar_t *wcs = L"€200 for this spoon?"; // 20 characters
12
13 size_t byte_count;
14
562 Chapter 62. <stdlib.h> Standard Library Functions
See Also
mblen(), wctomb(), mbstowcs(), setlocale()
Chapter 63
This header provides a macro noreturn that is a handy alias for _Noreturn.
Use this macro to indicate to the compiler that a function will never return to the caller. It’s undefined
behavior if the so-marked function does return.
Here’s a usage example:
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdnoreturn.h>
4
12 int main(void)
13 {
14 foo();
15 }
563
564 Chapter 63. <stdnoreturn.h> Macros for Non-Returning Functions
Chapter 64
Function Description
memchr() Find the first occurrence of a character in memory.
memcmp() Compare two regions of memory.
memcpy() Copy a region of memory to another.
memmove() Move a (potentially overlapping) region of
memory.
memset() Set a region of memory to a value.
strcat() Concatenate (join) two strings together.
strchr() Find the first occurrence of a character in a string.
strcmp() Compare two strings.
strcoll() Compare two strings accounting for locale.
strcpy() Copy a string.
strcspn() Find length of a string not consisting of a set of
characters.
strerror() Return a human-readable error message for a
given code.
strlen() Return the length of a string.
strncat() Concatenate (join) two strings, length-limited.
strncmp() Compare two strings, length-limited.
strncpy() Copy two strings, length-limited.
strpbrk() Search a string for one of a set of character.
strrchr() Find the last occurrence of a character in a string.
strspn() Find length of a string consisting of a set of
characters.
strstr() Find a substring in a string.
strtok() Tokenize a string.
strxfrm() Prepare a string for comparison as if by
strcoll().
As has been mentioned earlier in the guide, a string in C is a sequence of bytes in memory, terminated
by a NUL character (‘\0’). The NUL at the end is important, since it lets all these string functions (and
printf() and puts() and everything else that deals with a string) know where the end of the string
actually is.
Fortunately, when you operate on a string using one of these many functions available to you, they add
the NUL terminator on for you, so you actually rarely have to keep track of it yourself. (Sometimes you
do, especially if you’re building a string from scratch a character at a time or something.)
In this section you’ll find functions for pulling substrings out of strings, concatenating strings together,
getting the length of a string, and so forth and so on.
565
566 Chapter 64. <string.h> String Manipulation
Synopsis
#include <string.h>
void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
Description
These functions copy memory—as many bytes as you want! From source to destination!
The main difference between the two is that memcpy() cannot safely copy overlapping memory regions,
whereas memmove() can.
On the one hand, I’m not sure why you’d want to ever use memcpy() instead of memmove(), but I’ll bet
it’s possibly more performant.
The parameters are in a particular order: destination first, then source. I remember this order because it
behaves like an “=” assignment: the destination is on the left.
Return Value
Both functions return whatever you passed in for parameter s1 for your convenience.
Example
1 #include <string.h>
2
3 int main(void)
4 {
5 char s[100] = "Goats";
6 char t[100];
7
See Also
strcpy(), strncpy()
Synopsis
#include <string.h>
Description
These functions copy a string from one address to another, stopping at the NUL terminator on the
srcstring.
strncpy() is just like strcpy(), except only the first n characters are actually copied. Beware that
if you hit the limit, n before you get a NUL terminator on the src string, your dest string won’t be
NUL-terminated. Beware! BEWARE!
(If the src string has fewer than n characters, it works just like strcpy().)
You can terminate the string yourself by sticking the '\0' in there yourself:
char s[10];
char foo = "My hovercraft is full of eels."; // more than 10 chars
Return Value
Both functions return dest for your convenience, at no extra charge.
Example
1 #include <string.h>
2
3 int main(void)
4 {
5 char *src = "hockey hockey hockey hockey hockey hockey hockey hockey";
6 char dest[20];
7
8 int len;
9
12 len = strlen(dest);
13
14 // tricky, but let's use some pointer arithmetic and math to append
15 // as much of src as possible onto the end of dest, -1 on the length to
16 // leave room for the terminator:
17 strncpy(dest+len, src, sizeof(dest)-len-1);
18
See Also
memcpy(), strcat(), strncat()
568 Chapter 64. <string.h> String Manipulation
Synopsis
#include <string.h>
Description
“Concatenate”, for those not in the know, means to “stick together”. These functions take two strings, and
stick them together, storing the result in the first string.
These functions don’t take the size of the first string into account when it does the concatenation. What
this means in practical terms is that you can try to stick a 2 megabyte string into a 10 byte space. This will
lead to unintended consequences, unless you intended to lead to unintended consequences, in which case
it will lead to intended unintended consequences.
Technical banter aside, your boss and/or professor will be irate.
If you want to make sure you don’t overrun the first string, be sure to check the lengths of the strings first
and use some highly technical subtraction to make sure things fit.
You can actually only concatenate the first n characters of the second string by using strncat() and
specifying the maximum number of characters to copy.
Return Value
Both functions return a pointer to the destination string, like most of the string-oriented functions.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char dest[30] = "Hello";
7 char *src = ", World!";
8 char numbers[] = "12345678";
9
12 strcat(dest, src);
13 printf("dest after strcat: \"%s\"\n", dest); // "Hello, world!"
14
Notice I mixed and matched pointer and array notation there with src and numbers; this is just fine with
string functions.
See Also
strlen()
64.4. strcmp(), strncmp(), memcmp() 569
Synopsis
#include <string.h>
Description
All these functions compare chunks of bytes in memory.
strcmp() and strncmp() operate on NUL-terminated strings, whereas memcmp() will compare the num-
ber of bytes you specify, brazenly ignoring any NUL characters it finds along the way.
strcmp() compares the entire string down to the end, while strncmp() only compares the first n char-
acters of the strings.
It’s a little funky what they return. Basically it’s a difference of the strings, so if the strings are the same,
it’ll return zero (since the difference is zero). It’ll return non-zero if the strings differ; basically it will find
the first mismatched character and return less-than zero if that character in s1 is less than the corresponding
character in s2. It’ll return greater-than zero if that character in s1 is greater than that in s2.
So if they return 0, the comparison was equal (i.e. the difference was 0.)
These functions can be used as comparison functions for qsort() if you have an array of char*s you
want to sort.
Return Value
Returns zero if the strings or memory are the same, less-than zero if the first different character in s1 is
less than that in s2, or greater-than zero if the first difference character in s1 is greater than than in s2.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char *s1 = "Muffin";
7 char *s2 = "Muffin Sandwich";
8 char *s3 = "Muffin";
9
16 if (strcmp(s1, s2) == 0)
570 Chapter 64. <string.h> String Manipulation
19 if (strcmp(s1, s3) == 0)
20 printf("This will print because s1 and s3 are the same\n");
21
28 if (!strcmp(s1, s3))
29 printf("The strings are the same!\n");
30
See Also
memcmp(), qsort()
64.5 strcoll()
Compare two strings accounting for locale
Synopsis
#include <string.h>
Description
This is basically strcmp(), except that it handles accented characters better depending on the locale.
For example, my strcmp() reports that the character “é” (with accent) is greater than “f”. But that’s
hardly useful for alphabetizing.
By setting the LC_COLLATE locale value (either by name or via LC_ALL), you can have strcoll() sort
in a way that’s more meaningful by the current locale. For example, by having “é” appear sanely before
“f”.
It’s also a lot slower than strcmp() so use it only if you have to. See strxfrm() for a potential speedup.
Return Value
Like the other string comparison functions, strcoll() returns a negative value if s1 is less than s2, or a
positive value if s1 is greater than s2. Or 0 if they are equal.
Example
1 #include <stdio.h>
2 #include <string.h>
3 #include <locale.h>
4
64.6. strxfrm() 571
5 int main(void)
6 {
7 setlocale(LC_ALL, "");
8
See Also
strcmp()
64.6 strxfrm()
Transform a string for comparing based on locale
Synopsis
#include <string.h>
size_t strxfrm(char * restrict s1, const char * restrict s2, size_t n);
Description
This is a strange little function, so bear with me.
Firstly, if you haven’t done so, get familiar with strcoll() because this is closely related to that.
OK! Now that you’re back, you can think of strxfrm() as the first part of the strcoll() internals.
Basically, strcoll() has to transform a string into a form that can be compared with strcmp(). And it
does this with strxfrm() for both strings every time you call it.
strxform() takes string s2 and transforms it (readies it for strcmp()) storing the result in s1. It writes
no more than n bytes, protecting us from terrible buffer overflows.
But hang on—there’s another mode! If you pass NULL for s1 and 0 for n, it will return the number of
bytes that the transformed string would have used1 . This is useful if you need to allocate some space to
hold the transformed string before you strcmp() it against another.
What I’m getting at, not to be too blunt, is that strcoll() is slow compared to strcmp(). It does a lot
of extra work running strxfrm() on all its strings.
In fact, we can see how it works by writing our own like this:
1 int my_strcoll(char *s1, char *s2)
2 {
3 // Use n = 0 to just get the lengths of the transformed strings
4 int len1 = strxfrm(NULL, s1, 0) + 1;
5 int len2 = strxfrm(NULL, s2, 0) + 1;
6
1
It always returns the number of bytes the transformed string took, but in this case because s1 was NULL, it doesn’t actually write
a transformed string.
572 Chapter 64. <string.h> String Manipulation
22 return result;
23 }
You see on lines 12, 13, and 16, above how we transform the two input strings and then call strcmp() on
the result.
So why do we have this function? Can’t we just call strcoll() and be done with it?
The idea is that if you have one string that you’re going to be comparing against a whole lot of other ones,
maybe you just want to transform that string one time, then use the faster strcmp() saving yourself a
bunch of the work we had to do in the function, above.
We’ll do that in the example.
Return Value
Returns the number of bytes in the transformed sequence. If the value is greater than n, the results in s1
are meaningless.
Example
1 #include <stdio.h>
2 #include <string.h>
3 #include <locale.h>
4 #include <stdlib.h>
5
13 strxfrm(d, s, len);
14
15 return d;
16 }
17
26 free(s1_transformed);
27
28 return result;
29 }
30
31 int main(void)
32 {
33 setlocale(LC_ALL, "");
34
43 free(s);
44 }
See Also
strcoll()
Synopsis
#include <string.h>
Description
The functions strchr() and strrchr find the first or last occurrence of a letter in a string, respectively.
(The extra “r” in strrchr() stands for “reverse”–it looks starting at the end of the string and working
backward.) Each function returns a pointer to the char in question, or NULL if the letter isn’t found in the
string.
memchr() is similar, except that instead of stopping on the first NUL character, it continues searching for
however many bytes you specify.
Quite straightforward.
One thing you can do if you want to find the next occurrence of the letter after finding the first, is call the
function again with the previous return value plus one. (Remember pointer arithmetic?) Or minus one if
you’re looking in reverse. Don’t accidentally go off the end of the string!
574 Chapter 64. <string.h> String Manipulation
Return Value
Returns a pointer to the occurrence of the letter in the string, or NULL if the letter is not found.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 // "Hello, world!"
7 // ^ ^ ^
8 // A B C
9
Output:
Found a 'B' here: BIG BROWN BAT BIT BEEJ
Found a 'B' here: BROWN BAT BIT BEEJ
Found a 'B' here: BAT BIT BEEJ
Found a 'B' here: BIT BEEJ
Found a 'B' here: BEEJ
Synopsis
#include <string.h>
Description
strspn() will tell you the length of a string consisting entirely of the set of characters in accept. That
is, it starts walking down str until it finds a character that is not in the set (that is, a character that is not
to be accepted), and returns the length of the string so far.
64.9. strpbrk() 575
strcspn() works much the same way, except that it walks down str until it finds a character in the
reject set (that is, a character that is to be rejected.) It then returns the length of the string so far.
Return Value
The length of the string consisting of all characters in accept (for strspn()), or the length of the string
consisting of all characters except reject (for strcspn()).
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char str1[] = "a banana";
7 char str2[] = "the bolivian navy on maenuvers in the south pacific";
8 int n;
9
10 // how many letters in str1 until we reach something that's not a vowel?
11 n = strspn(str1, "aeiou");
12 printf("%d\n", n); // n == 1, just "a"
13
See Also
strchr(), strrchr()
64.9 strpbrk()
Search a string for one of a set of characters
Synopsis
#include <string.h>
Description
This function searches string s1 for any of the characters that are found in string s2.
It’s just like how strchr() searches for a specific character in a string, except it will match any of the
characters found in s2.
Think of the power!
576 Chapter 64. <string.h> String Manipulation
Return Value
Returns a pointer to the first character matched in s1, or NULL if the string isn’t found.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 // p points here after strpbrk
7 // v
8 char *s1 = "Hello, world!";
9 char *s2 = "dow!"; // Match any of these chars
10
See Also
strchr(), memchr()
64.10 strstr()
Find a string in another string
Synopsis
#include <string.h>
Description
Let’s say you have a big long string, and you want to find a word, or whatever substring strikes your fancy,
inside the first string. Then strstr() is for you! It’ll return a pointer to the substr within the str!
Return Value
You get back a pointer to the occurrence of the substr inside the str, or NULL if the substring can’t be
found.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char *str = "The quick brown fox jumped over the lazy dogs.";
7 char *p;
8
64.11. strtok() 577
9 p = strstr(str, "lazy");
10 printf("%s\n", p == NULL? "null": p); // "lazy dogs."
11
See Also
strchr(), strrchr(), strspn(), strcspn()
64.11 strtok()
Tokenize a string
Synopsis
#include <string.h>
Description
If you have a string that has a bunch of separators in it, and you want to break that string up into individual
pieces, this function can do it for you.
The usage is a little bit weird, but at least whenever you see the function in the wild, it’s consistently weird.
Basically, the first time you call it, you pass the string, str that you want to break up in as the first
argument. For each subsequent call to get more tokens out of the string, you pass NULL. This is a little
weird, but strtok() remembers the string you originally passed in, and continues to strip tokens off for
you.
Note that it does this by actually putting a NUL terminator after the token, and then returning a pointer to
the start of the token. So the original string you pass in is destroyed, as it were. If you need to preserve
the string, be sure to pass a copy of it to strtok() so the original isn’t destroyed.
Return Value
A pointer to the next token. If you’re out of tokens, NULL is returned.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 // break up the string into a series of space or
7 // punctuation-separated words
8 char str[] = "Where is my bacon, dude?";
9 char *token;
10
13
Output:
Word: "Where"
Word: "is"
Word: "my"
Word: "bacon"
Word: "dude"
See Also
strchr(), strrchr(), strspn(), strcspn()
64.12 memset()
Set a region of memory to a certain value
Synopsis
#include <string.h>
Description
This function is what you use to set a region of memory to a particular value, namely c converted into
unsigned char.
Return Value
memset() returns whatever you passed in as s for happy convenience.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 struct banana {
7 float ripeness;
8 char *peel_color;
64.13. strerror() 579
9 int grams;
10 };
11
12 struct banana b;
13
See Also
memcpy(), memmove()
64.13 strerror()
Get a string version of an error number
Synopsis
#include <string.h>
Description
This function ties closely into perror() (which prints a human-readable error message corresponding to
errno). But instead of printing, strerror() returns a pointer to the locale-specific error message string.
So if you ever need that string back for some reason (e.g. you’re going to fprintf() it to a file or
something), this function will give it to you. All you need to do is pass in errno as an argument. (Recall
that errno gets set as an error status by a variety of functions.)
You can actually pass in any integer for errnum you want. The function will return some message, even
if the number doesn’t correspond to any known value for errno.
The values of errno and the strings returned by strerror() are system-dependent.
Return Value
A string error message corresponding to the given error number.
You are not allowed to modify the returned string.
Example
1 #include <stdio.h>
2 #include <string.h>
3 #include <errno.h>
4
5 int main(void)
6 {
7 FILE *fp = fopen("NONEXISTENT_FILE.TXT", "r");
8
580 Chapter 64. <string.h> String Manipulation
9 if (fp == NULL) {
10 char *errmsg = strerror(errno);
11 printf("Error %d opening file: %s\n", errno, errmsg);
12 }
13 }
Output:
Error 2 opening file: No such file or directory
See Also
perror()
64.14 strlen()
Returns the length of a string
Synopsis
#include <string.h>
Description
This function returns the length of the passed null-terminated string (not counting the NUL character at
the end). It does this by walking down the string and counting the bytes until the NUL character, so it’s a
little time consuming. If you have to get the length of the same string repeatedly, save it off in a variable
somewhere.
Return Value
Returns the number of bytes in the string. Note that this might be different than the number of characters
in a multibyte string.
Example
1 #include <stdio.h>
2 #include <string.h>
3
4 int main(void)
5 {
6 char *s = "Hello, world!"; // 13 characters
7
See Also
Chapter 65
These are type-generic macros that are wrappers around the math functions in <math.h> and <com-
plex.h>. This header includes both of those.
Deep down, these are implemented using type generics as described in the Types Part V chapter.
But on the surface, you can think of them as being able to use, say, the sqrt() function with any type
without needed to think about if it’s double or long double or even complex.
These are the defined macros—some of them don’t have a counterpart in the real or complex space. Type
suffixes are omitted in the table on the Real and Complex columns. None of the generic macros have type
suffixes.
581
582 Chapter 65. <tgmath.h> Type-Generic Math Functions
65.1 Example
Here’s an example where we call the type-generic sqrt() function on a variety of types.
1 #include <stdio.h>
2 #include <tgmath.h>
3
4 int main(void)
5 {
6 double x = 12.8;
7 long double y = 34.9;
8 double complex z = 1 + 2 * I;
9
10 double x_result;
11 long double y_result;
12 double complex z_result;
13
Output:
x_result: 3.577709
y_result: 5.907622
z_result: 1.272020 + 0.786151i
584 Chapter 65. <tgmath.h> Type-Generic Math Functions
Chapter 66
<threads.h> Multithreading
Functions
Function Description
call_once() Call a function one time no matter how many
threads try
cnd_broadcast() Wake up all threads waiting on a condition
variable
cnd_destroy() Free up resources from a condition variable
cnd_init() Initialize a condition variable to make it ready for
use
cnd_signal() Wake up a thread waiting on a condition variable
cnd_timedwait() Wait on a condition variable with a timeout
cnd_wait() Wait for a signal on a condition variable
mtx_destroy() Cleanup a mutex when done with it
mtx_init() Initialize a mutex for use
mtx_lock() Acquire a lock on a mutex
mtx_timedlock() Lock a mutex allowing for timeout
mtx_trylock() Try to lock a mutex, returning if not possible
mtx_unlock() Free a mutex when you’re done with the critical
section
thrd_create() Create a new thread of execution
thrd_current() Get the ID of the calling thread
thrd_detach() Automatically clean up threads when they exit
thrd_equal() Compare two thread descriptors for equality
thrd_exit() Stop and exit this thread
thrd_join() Wait for a thread to exit
thrd_yield() Stop running that other threads might run
tss_create() Create new thread-specific storage
tss_delete() Clean up a thread-specific storage variable
tss_get() Get thread-specific data
tss_set() Set thread-specific data
585
586 Chapter 66. <threads.h> Multithreading Functions
66.1 call_once()
Call a function one time no matter how many threads try
Synopsis
#include <threads.h>
Description
If you have a bunch of threads running over the same piece of code that calls a function, but you only
want that function to run one time, call_once() can help you out.
The catch is the function that is called doesn’t return anything and takes no arguments.
If you need more than that, you’ll have to set a threadsafe flag such as atomic_flag, or one that you
protect with a mutex.
To use this, you need to pass it a pointer to a function to execute, func, and also a pointer to a flag of type
once_flag.
once_flag is an opaque type, so all you need to know is that you initialize it to the value
ONCE_FLAG_INIT.
Return Value
Returns nothing.
Example
1 #include <stdio.h>
2 #include <threads.h>
3
6 void run_once_function(void)
7 {
8 printf("I'll only run once!\n");
9 }
10
15 printf("Thread running!\n");
16
17 call_once(&of, run_once_function);
18
19 return 0;
20 }
21
22 #define THREAD_COUNT 5
23
24 int main(void)
66.2. cnd_broadcast() 587
25 {
26 thrd_t t[THREAD_COUNT];
27
66.2 cnd_broadcast()
Wake up all threads waiting on a condition variable
Synopsis
#include <threads.h>
Description
This is just like cnd_signal() in that it wakes up threads that are waiting on a condition variable….
except instead of just rousing one thread, it wakes them all.
Of course, only one will get the mutex, and the rest will have to wait their turn. But instead of being
asleep waiting for a signal, they’ll be asleep waiting to reacquire the mutex. They’re rearin’ to go, in other
words.
This can make a difference in a specific set of circumstances where cnd_signal() might leave you
hanging.
If you’re relying on subsequent threads to issue the next cnd_signal(), but you have the cnd_wait()
in a while loop1 that doesn’t allow any threads to escape, you’ll be stuck. No more threads will be woken
up from the wait.
But if you cnd_broadcast(), all the threads will be woken, and presumably at least one of them will be
allowed to escape the while loop, freeing it up to broadcast the next wakeup when its work is done.
Return Value
Returns thrd_success or thrd_error depending on how well things went.
Example
In the example below, we launch a bunch of threads, but they’re only allowed to run if their ID matches
the current ID. If it doesn’t, they go back to waiting.
1
Which you should because of spurious wakeups.
588 Chapter 66. <threads.h> Multithreading Functions
If you cnd_signal() to wake the next thread, it might not be the one with the proper ID to run. If it’s
not, it goes back to sleep and we hang (because no thread is awake to hit cnd_signal() again).
But if you cnd_broadcast() to wake them all, then they’ll all try (one after another) to get out of the
while loop. And one of them will make it.
Try switching the cnd_broadcast() to cnd_signal() to see likely deadlocks. It doesn’t happen every
time, but usually does.
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
13 mtx_lock(&mutex);
14
19 if (id != current_id)
20 printf("THREAD %d: woke up, but it's not my turn!\n", id);
21 else
22 printf("THREAD %d: woke up, my turn! Let's go!\n", id);
23 }
24
25 current_id++;
26
29 //cnd_signal(&condvar);
30 cnd_broadcast(&condvar);
31 mtx_unlock(&mutex);
32
33 return 0;
34 }
35
36 #define THREAD_COUNT 5
37
38 int main(void)
39 {
40 thrd_t t[THREAD_COUNT];
41 int id[] = {4, 3, 2, 1, 0};
42
43 mtx_init(&mutex, mtx_plain);
44 cnd_init(&condvar);
45
52 mtx_destroy(&mutex);
53 cnd_destroy(&condvar);
54 }
See how THREAD 0 signaled that it was THREAD 1’s turn? But—bad news—it was THREAD 4 that got
woken up. So no one continued the process. cnd_broadcast() would have woken them all, so eventually
THREAD 1 would have run, gotten out of the while, and broadcast for the next thread to run.
See Also
cnd_signal(), mtx_lock(), mtx_unlock()
66.3 cnd_destroy()
Free up resources from a condition variable
590 Chapter 66. <threads.h> Multithreading Functions
Synopsis
#include <threads.h>
Description
This is the opposite of cnd_init() and should be called when all threads are done using a condition
variable.
Return Value
Returns nothing!
Example
General-purpose condition variable example here, but you can see the cnd_destroy() down at the end.
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
11 mtx_lock(&mutex);
12
13 printf("Thread: waiting...\n");
14 cnd_wait(&condvar, &mutex);
15 printf("Thread: running again!\n");
16
17 mtx_unlock(&mutex);
18
19 return 0;
20 }
21
22 int main(void)
23 {
24 thrd_t t;
25
26 mtx_init(&mutex, mtx_plain);
27 cnd_init(&condvar);
28
35 mtx_lock(&mutex);
36 printf("Main: signaling thread\n");
37 cnd_signal(&condvar);
38 mtx_unlock(&mutex);
39
66.4. cnd_init() 591
40 thrd_join(t, NULL);
41
42 mtx_destroy(&mutex);
43 cnd_destroy(&condvar); // <-- DESTROY CONDITION VARIABLE
44 }
Output:
Main creating thread
Thread: waiting...
Main: signaling thread
Thread: running again!
See Also
cnd_init()
66.4 cnd_init()
Initialize a condition variable to make it ready for use
Synopsis
#include <threads.h>
Description
This is the opposite of cnd_destroy(). This prepares a condition variable for use, doing behind-the-
scenes work on it.
Don’t use a condition variable without calling this first!
Return Value
If all goes well, returns thrd_success. It all doesn’t go well, it could return thrd_nomem if the system
is out of memory, or thread_error in the case of any other error.
Example
General-purpose condition variable example here, but you can see the cnd_init() down at the start of
main().
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
11 mtx_lock(&mutex);
12
592 Chapter 66. <threads.h> Multithreading Functions
13 printf("Thread: waiting...\n");
14 cnd_wait(&condvar, &mutex);
15 printf("Thread: running again!\n");
16
17 mtx_unlock(&mutex);
18
19 return 0;
20 }
21
22 int main(void)
23 {
24 thrd_t t;
25
26 mtx_init(&mutex, mtx_plain);
27 cnd_init(&condvar); // <-- INITIALIZE CONDITION VARIABLE
28
35 mtx_lock(&mutex);
36 printf("Main: signaling thread\n");
37 cnd_signal(&condvar);
38 mtx_unlock(&mutex);
39
40 thrd_join(t, NULL);
41
42 mtx_destroy(&mutex);
43 cnd_destroy(&condvar);
44 }
Output:
Main creating thread
Thread: waiting...
Main: signaling thread
Thread: running again!
See Also
cnd_destroy()
66.5 cnd_signal()
Wake up a thread waiting on a condition variable
Synopsis
#include <threads.h>
Description
If you have a thread (or a bunch of threads) waiting on a condition variable, this function will wake one
of them up to run.
Compare to cnd_broadcast() that wakes up all the threads. See the cnd_broadcast() page for more
information on when you’re want to use that versus this.
Return Value
Returns thrd_success or thrd_error depending on how happy your program is.
Example
General-purpose condition variable example here, but you can see the cnd_signal() in the middle of
main().
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
11 mtx_lock(&mutex);
12
13 printf("Thread: waiting...\n");
14 cnd_wait(&condvar, &mutex);
15 printf("Thread: running again!\n");
16
17 mtx_unlock(&mutex);
18
19 return 0;
20 }
21
22 int main(void)
23 {
24 thrd_t t;
25
26 mtx_init(&mutex, mtx_plain);
27 cnd_init(&condvar);
28
35 mtx_lock(&mutex);
36 printf("Main: signaling thread\n");
37 cnd_signal(&condvar); // <-- SIGNAL CHILD THREAD HERE!
38 mtx_unlock(&mutex);
39
40 thrd_join(t, NULL);
41
42 mtx_destroy(&mutex);
594 Chapter 66. <threads.h> Multithreading Functions
43 cnd_destroy(&condvar);
44 }
Output:
Main creating thread
Thread: waiting...
Main: signaling thread
Thread: running again!
See Also
cnd_init(), cnd_destroy()
66.6 cnd_timedwait()
Wait on a condition variable with a timeout
Synopsis
#include <threads.h>
Description
This is like cnd_wait() except we get to specify a timeout, as well.
Note that the thread still must reacquire the mutex to get more work done even after the timeout. The
the main difference is that regular cnd_wait() will only try to get the mutex after a cnd_signal()
or cnd_broadcast(), whereas cnd_timedwait() will do that, too, and try to get the mutex after the
timeout.
The timeout is specified as an absolute UTC time since Epoch. You can get this with the timespec_get()
function and then add values on to the result to timeout later than now, as shown in the example.
Beware that you can’t have more than 999999999 nanoseconds in the tv_nsec field of the struct time-
spec. Mod those so they stay in range.
Return Value
If the thread wakes up for a non-timeout reason (e.g. signal or broadcast), returns thrd_success. If
woken up due to timeout, returns thrd_timedout. Otherwise returns thrd_error.
Example
This example has a thread wait on a condition variable for a maximum of 1.75 seconds. And it always
times out because no one ever sends a signal. Tragic.
1 #include <stdio.h>
2 #include <time.h>
3 #include <threads.h>
4
5 cnd_t condvar;
6 mtx_t mutex;
7
66.6. cnd_timedwait() 595
12 mtx_lock(&mutex);
13
27 printf("Thread: waiting...\n");
28 int r = cnd_timedwait(&condvar, &mutex, &ts);
29
30 switch (r) {
31 case thrd_success:
32 printf("Thread: signaled!\n");
33 break;
34
35 case thrd_timedout:
36 printf("Thread: timed out!\n");
37 return 1;
38
39 case thrd_error:
40 printf("Thread: Some kind of error\n");
41 return 2;
42 }
43
44 mtx_unlock(&mutex);
45
46 return 0;
47 }
48
49 int main(void)
50 {
51 thrd_t t;
52
53 mtx_init(&mutex, mtx_plain);
54 cnd_init(&condvar);
55
62 thrd_join(t, NULL);
63
64 mtx_destroy(&mutex);
65 cnd_destroy(&condvar);
596 Chapter 66. <threads.h> Multithreading Functions
66 }
Output:
Main creating thread
Thread: waiting...
Thread: timed out!
See Also
cnd_wait(), timespec_get()
66.7 cnd_wait()
Wait for a signal on a condition variable
Synopsis
#include <threads.h>
Description
This puts the calling thread to sleep until it is awakened by a call to cnd_signal() or cnd_broadcast().
Return Value
If everything’s fantastic, returns thrd_success. Otherwise it returns thrd_error to report that some-
thing has gone fantastically, horribly awry.
Example
General-purpose condition variable example here, but you can see the cnd_wait() in the run() function.
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
11 mtx_lock(&mutex);
12
13 printf("Thread: waiting...\n");
14 cnd_wait(&condvar, &mutex); // <-- WAIT HERE!
15 printf("Thread: running again!\n");
16
17 mtx_unlock(&mutex);
18
19 return 0;
20 }
21
66.8. mtx_destroy() 597
22 int main(void)
23 {
24 thrd_t t;
25
26 mtx_init(&mutex, mtx_plain);
27 cnd_init(&condvar);
28
35 mtx_lock(&mutex);
36 printf("Main: signaling thread\n");
37 cnd_signal(&condvar); // <-- SIGNAL CHILD THREAD HERE!
38 mtx_unlock(&mutex);
39
40 thrd_join(t, NULL);
41
42 mtx_destroy(&mutex);
43 cnd_destroy(&condvar);
44 }
Output:
Main creating thread
Thread: waiting...
Main: signaling thread
Thread: running again!
See Also
cnd_timedwait()
66.8 mtx_destroy()
Cleanup a mutex when done with it
Synopsis
#include <threads.h>
Description
The opposite of mtx_init(), this function frees up any resources associated with the given mutex.
You should call this when all threads are done using the mutex.
Return Value
Returns nothing, the selfish ingrate!
598 Chapter 66. <threads.h> Multithreading Functions
Example
General-purpose mutex example here, but you can see the mtx_destroy() down at the end.
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
13 mtx_lock(&mutex);
14
18 mtx_unlock(&mutex);
19
20 return 0;
21 }
22
23 #define THREAD_COUNT 5
24
25 int main(void)
26 {
27 thrd_t t[THREAD_COUNT];
28
29 mtx_init(&mutex, mtx_plain);
30
Output:
Thread: I got 0!
Thread: I got 1!
Thread: I got 2!
Thread: I got 3!
Thread: I got 4!
See Also
mtx_init()
66.9 mtx_init()
Initialize a mutex for use
66.9. mtx_init() 599
Synopsis
#include <threads.h>
Description
Before you can use a mutex variable, you have to initialize it with this call to get it all prepped and ready
to go.
But wait! It’s not quite that simple. You have to tell it what type of mutex you want to create.
Type Description
mtx_plain Regular ol’ mutex
mtx_timed Mutex that supports timeouts
mtx_plain|mtx_recursive Recursive mutex
mtx_timed|mtx_recursive Recursive mutex that supports timeouts
As you can see, you can make a plain or timed mutex recursive by bitwise-ORing the value with
mtx_recursive.
“Recursive” means that the holder of a lock can call mtx_lock() multiple times on the same lock. (They
have to unlock it an equal number of times before anyone else can take the mutex.) This might ease coding
from time to time, especially if you call a function that needs to lock the mutex when you already hold
the mutex.
And the timeout gives a thread a chance to try to get the lock for a while, but then bail out if it can’t get it
in that timeframe. You use the mtx_timedlock() function with mtx_timed mutexes.
Return Value
Returns thrd_success in a perfect world, and potentially thrd_error in an imperfect one.
Example
General-purpose mutex example here, but you can see the mtx_init() down at the top of main():
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
13 mtx_lock(&mutex);
14
18 mtx_unlock(&mutex);
19
20 return 0;
600 Chapter 66. <threads.h> Multithreading Functions
21 }
22
23 #define THREAD_COUNT 5
24
25 int main(void)
26 {
27 thrd_t t[THREAD_COUNT];
28
Output:
Thread: I got 0!
Thread: I got 1!
Thread: I got 2!
Thread: I got 3!
Thread: I got 4!
See Also
mtx_destroy()
66.10 mtx_lock()
Acquire a lock on a mutex
Synopsis
#include <threads.h>
Description
If you’re a thread and want to enter a critical section, do I have the function for you!
A thread that calls this function will wait until it can acquire the mutex, then it will grab it, wake up, and
run!
If the mutex is recursive and is already locked by this thread, it will be locked again and the lock count
will increase. If the mutex is not recursive and the thread already holds it, this call will error out.
Return Value
Returns thrd_success on goodness and thrd_error on badness.
66.11. mtx_timedlock() 601
Example
General-purpose mutex example here, but you can see the mtx_lock() in the run() function:
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
18 mtx_unlock(&mutex);
19
20 return 0;
21 }
22
23 #define THREAD_COUNT 5
24
25 int main(void)
26 {
27 thrd_t t[THREAD_COUNT];
28
Output:
Thread: I got 0!
Thread: I got 1!
Thread: I got 2!
Thread: I got 3!
Thread: I got 4!
See Also
mtx_unlock(), mtx_trylock(), mtx_timedlock()
66.11 mtx_timedlock()
Lock a mutex allowing for timeout
602 Chapter 66. <threads.h> Multithreading Functions
Synopsis
#include <threads.h>
Description
This is just like mtx_lock() except you can add a timeout if you don’t want to wait forever.
The timeout is specified as an absolute UTC time since Epoch. You can get this with the timespec_get()
function and then add values on to the result to timeout later than now, as shown in the example.
Beware that you can’t have more than 999999999 nanoseconds in the tv_nsec field of the struct time-
spec. Mod those so they stay in range.
Return Value
If everything works and the mutex is obtained, returns thrd_success. If a timeout happens first, returns
thrd_timedout.
Example
This example has a thread wait on a mutex for a maximum of 1.75 seconds. And it always times out
because no one ever sends a signal.
1 #include <stdio.h>
2 #include <time.h>
3 #include <threads.h>
4
5 mtx_t mutex;
6
27 switch (r) {
28 case thrd_success:
29 printf("Thread: grabbed lock!\n");
30 break;
31
32 case thrd_timedout:
66.12. mtx_trylock() 603
36 case thrd_error:
37 printf("Thread: Some kind of error\n");
38 break;
39 }
40
41 mtx_unlock(&mutex);
42
43 return 0;
44 }
45
46 int main(void)
47 {
48 thrd_t t;
49
50 mtx_init(&mutex, mtx_plain);
51
52 mtx_lock(&mutex);
53
60 mtx_unlock(&mutex);
61
62 thrd_join(t, NULL);
63
64 mtx_destroy(&mutex);
65 }
Output:
Main creating thread
Thread: waiting for lock...
Thread: timed out!
See Also
mtx_lock(), mtx_trylock(), timespec_get()
66.12 mtx_trylock()
Try to lock a mutex, returning if not possible
Synopsis
#include <threads.h>
Description
This works just like mtx_lock except that it returns instantly if a lock can’t be obtained.
The spec notes that there’s a chance that mtx_trylock() might spuriously fail with thrd_busy even if
there are no other threads holding the lock. I’m not sure why this is, but you should defensively code
against it.
Return Value
Returns thrd_success if all’s well. Or thrd_busy if some other thread holds the lock. Or thrd_error,
which means something went right. I mean “wrong”.
Example
1 #include <stdio.h>
2 #include <time.h>
3 #include <threads.h>
4
5 mtx_t mutex;
6
13 switch (r) {
14 case thrd_success:
15 printf("Thread %d: grabbed lock!\n", id);
16 break;
17
18 case thrd_busy:
19 printf("Thread %d: lock already taken :(\n", id);
20 return 1;
21
22 case thrd_error:
23 printf("Thread %d: Some kind of error\n", id);
24 return 2;
25 }
26
27 mtx_unlock(&mutex);
28
29 return 0;
30 }
31
32 #define THREAD_COUNT 5
33
34 int main(void)
35 {
36 thrd_t t[THREAD_COUNT];
37 int id[THREAD_COUNT];
38
39 mtx_init(&mutex, mtx_plain);
40
45
49 mtx_destroy(&mutex);
50 }
See Also
mtx_lock(), mtx_timedlock(), mtx_unlock()
66.13 mtx_unlock()
Free a mutex when you’re done with the critical section
Synopsis
#include <threads.h>
Description
After you’ve done all the dangerous stuff you have to do, wherein the involved threads should not be
stepping on each other’s toes… you can free up your stranglehold on the mutex by calling mtx_unlock().
Return Value
Returns thrd_success on success. Or thrd_error on error. It’s not very original in this regard.
Example
General-purpose mutex example here, but you can see the mtx_unlock() in the run() function:
1 #include <stdio.h>
2 #include <threads.h>
3
4 cnd_t condvar;
5 mtx_t mutex;
6
13 mtx_lock(&mutex);
14
606 Chapter 66. <threads.h> Multithreading Functions
20 return 0;
21 }
22
23 #define THREAD_COUNT 5
24
25 int main(void)
26 {
27 thrd_t t[THREAD_COUNT];
28
29 mtx_init(&mutex, mtx_plain);
30
37 mtx_destroy(&mutex);
38 }
Output:
Thread: I got 0!
Thread: I got 1!
Thread: I got 2!
Thread: I got 3!
Thread: I got 4!
See Also
mtx_lock(), mtx_timedlock(), mtx_trylock()
66.14 thrd_create()
Create a new thread of execution
Synopsis
#include <threads.h>
Description
Now you have the POWER!
Right?
This is how you launch new threads to make your program do multiple things at once2 !
2
Well, as at least as many things as you have free cores. Your OS will schedule them as it can.
66.14. thrd_create() 607
In order to make this happen, you need to pass a pointer to a thrd_t that will be used to represent the
thread you’re spawning.
That thread will start running the function you pass a pointer to in func. This is a value of type
thrd_start_t, which is a pointer to a function that returns an int and takes a single void* as a
parameter, i.e.:
int thread_run_func(void *arg)
And, as you might have guessed, the pointer you pass to thrd_create() for the arg parameter is passed
on to the func function. This is how you can give additional information to the thread when it starts up.
Of course, for arg, you have to be sure to pass a pointer to an object that is thread-safe or per-thread.
If the thread returns from the function, it exits just as if it had called thrd_exit().
Finally, the value that the func function returns can be picked up by the parent thread with thrd_join().
Return Value
In the case of goodness, returns thrd_success. If you’re out of memory, will return thrd_nomem. Oth-
erwise, thrd_error.
Example
1 #include <stdio.h>
2 #include <threads.h>
3
10 return id;
11 }
12
13 #define THREAD_COUNT 5
14
15 int main(void)
16 {
17 thrd_t t[THREAD_COUNT];
18 int id[THREAD_COUNT]; // One of these per thread
19
28 thrd_join(t[i], &res);
29
See Also
thrd_exit(), thrd_join()
66.15 thrd_current()
Get the ID of the calling thread
Synopsis
#include <threads.h>
thrd_t thrd_current(void);
Description
Each thread has an opaque ID of type thrd_t. This is the value we see get initialized when we call
thrd_create().
But what if you want to get the ID of the currently running thread?
No problem! Just call this function and it will be returned to you.
Why? Who knows!
Well, to be honest, I could see it being used a couple places.
1. You could use it to have a thread detach itself with thrd_detach(). I’m not sure why you’d want
to do this, however.
2. You could use it to compare this thread’s ID with another you have stored in a variable somewhere
by using the thrd_equal() function. Seems like the most legit use.
3. …
4. Profit!
If anyone has another use, please let me know.
Return Value
Returns the calling thread’s ID.
Example
Here’s a general example that shows getting the current thread ID and comparing it to a previously-
recorded thread ID and taking exciting action based on the result! Starring Arnold Schwarzenegger!
66.16. thrd_detach() 609
1 #include <stdio.h>
2 #include <threads.h>
3
4 thrd_t first_thread_id;
5
12 if (thrd_equal(my_id, first_thread_id))
13 printf("I'm the first thread!\n");
14 else
15 printf("I'm not the first!\n");
16
17 return 0;
18 }
19
20 int main(void)
21 {
22 thrd_t t;
23
27 thrd_join(first_thread_id, NULL);
28 thrd_join(t, NULL);
29 }
Output:
Come on, you got what you want, Cohaagen! Give deez people ay-ah!
No, wait, that’s an Arnold Schwarzenegger quote from Total Recall, one of the best science fiction films
of all time. Watch it now and then come back to finish this reference page.
Man–what an ending! And Johnny Cab? So excellent. Anyway!
Output:
I'm the first thread!
I'm not the first!
See Also
thrd_equal(), thrd_detach()
66.16 thrd_detach()
Automatically clean up threads when they exit
Synopsis
#include <threads.h>
Description
Normally you have to thrd_join() to get resources associated with a deceased thread cleaned up. (Most
notably, its exit status is still floating around waiting to get picked up.)
But if you call thrd_detach() on the thread first, manual cleanup isn’t necessary. They just exit and are
cleaned up by the OS.
(Note that when the main thread dies, all the threads die in any case.)
Return Value
thrd_success if the thread successfully detaches, thrd_error otherwise.
Example
1 #include <stdio.h>
2 #include <threads.h>
3
4 thrd_t first_thread_id;
5
10 printf("Thread running!\n");
11
12 return 0;
13 }
14
15 #define THREAD_COUNT 5
16
17 int main(void)
18 {
19 thrd_t t;
20
26 // No need to thrd_join()!
27
See Also
thrd_join(), thrd_exit()
66.17 thrd_equal()
Compare two thread descriptors for equality
66.17. thrd_equal() 611
Synopsis
#include <threads.h>
Description
If you have two thread descriptors in thrd_t variables, you can test them for equality with this function.
For example, maybe one of the threads has special powers the others don’t, and the run function needs to
be able to tell them apart, as in the example.
Return Value
Returns non-zero if the threads are equal. Returns 0 if they’re not.
Example
Here’s a general example that shows getting the current thread ID and comparing it to a previously-
recorded thread ID and taking boring action based on the result.
1 #include <stdio.h>
2 #include <threads.h>
3
4 thrd_t first_thread_id;
5
17 return 0;
18 }
19
20 int main(void)
21 {
22 thrd_t t;
23
27 thrd_join(first_thread_id, NULL);
28 thrd_join(t, NULL);
29 }
Output:
I'm the first thread!
I'm not the first!
See Also
thrd_current()
612 Chapter 66. <threads.h> Multithreading Functions
66.18 thrd_exit()
Stop and exit this thread
Synopsis
#include <threads.h>
Description
A thread commonly exits by returning from its run function. But if it wants to exit early (perhaps from
deeper in the call stack), this function will get that done.
The res code can be picked up by a thread calling thrd_join(), and is equivalent to returning a value
from the run function.
Like with returning from the run function, this will also properly clean up all the thread-specific storage
associated with this thread—all the destructors for the threads TSS variables will be called. If there are any
remaining TSS variables with destructors after the first round of destruction3 , the remaining destructors
will be called. This happens repeatedly until there are no more, or the number of rounds of carnage reaches
TSS_DTOR_ITERATIONS.
Return Value
This function never returns because the thread calling it is killed in the process. Trippy!
Example
Threads in this example exit early with result 22 if they get a NULL value for arg.
1 #include <stdio.h>
2 #include <threads.h>
3
4 thrd_t first_thread_id;
5
10 if (arg == NULL)
11 thrd_exit(22);
12
13 return 0;
14 }
15
16 #define THREAD_COUNT 5
17
18 int main(void)
19 {
20 thrd_t t[THREAD_COUNT];
21
3
For example, if a destructor caused more variables to be set.
66.19. thrd_join() 613
25
Output:
Thread 0 exited with code 0
Thread 1 exited with code 0
Thread 2 exited with code 22
Thread 3 exited with code 0
Thread 4 exited with code 0
See Also
thrd_join()
66.19 thrd_join()
Wait for a thread to exit
Synopsis
#include <threads.h>
Description
When a parent thread fires off some child threads, it can wait for them to complete with this call
Return Value
Example
Threads in this example exit early with result 22 if they get a NULL value for arg. The parent thread picks
up this result code with thrd_join().
1 #include <stdio.h>
2 #include <threads.h>
3
4 thrd_t first_thread_id;
5
10 if (arg == NULL)
11 thrd_exit(22);
614 Chapter 66. <threads.h> Multithreading Functions
12
13 return 0;
14 }
15
16 #define THREAD_COUNT 5
17
18 int main(void)
19 {
20 thrd_t t[THREAD_COUNT];
21
25
Output:
Thread 0 exited with code 0
Thread 1 exited with code 0
Thread 2 exited with code 22
Thread 3 exited with code 0
Thread 4 exited with code 0
See Also
thrd_exit()
66.20 thrd_sleep()
Sleep for a specific number of seconds and nanoseconds
Synopsis
#include <threads.h>
Description
This function puts the current thread to sleep for a while4 allowing other threads to run.
The calling thread will wake up after the time has elapsed, or if it gets interrupted by a signal or something.
If it doesn’t get interrupted, it’ll sleep at least as long as you asked. Maybe a tad longer. You know how
hard it can be to get out of bed.
The structure looks like this:
struct timespec {
time_t tv_sec; // Seconds
4
Unix-like systems have a sleep() syscall that sleeps for an integer number of seconds. But thrd_sleep() is likely more
portable and gives subsecond resolution, besides!
66.21. thrd_yield() 615
Don’t set tv_nsec greater than 999,999,999. I can’t see what officially happens if you do, but on my
system thrd_sleep() returns -2 and fails.
Return Value
Returns 0 on timeout, or -1 if interrupted by a signal. Or any negative value on some other error. Weirdly,
the spec allows this “other error negative value” to also be -1, so good luck with that.
Example
1 #include <stdio.h>
2 #include <threads.h>
3
4 int main(void)
5 {
6 // Sleep for 3.25 seconds
7 thrd_sleep(&(struct timespec){.tv_sec=3, .tv_nsec=250000000}, NULL);
8
9 return 0;
10 }
See Also
thrd_yield()
66.21 thrd_yield()
Stop running that other threads might run
Synopsis
#include <threads.h>
void thrd_yield(void);
Description
If you have a thread that’s hogging the CPU and you want to give your other threads time to run, you
can call thrd_yield(). If the system sees fit, it will put the calling thread to sleep and one of the other
threads will run instead.
It’s a good way to be “polite” to the other threads in your program if you want the encourage them to run
instead.
Return Value
Returns nothing!
Example
This example’s kinda poor because the OS is probably going to reschedule threads on the output anyway,
but it gets the point across.
616 Chapter 66. <threads.h> Multithreading Functions
The main thread is giving other threads a chance to run after every block of dumb work it does.
1 #include <stdio.h>
2 #include <threads.h>
3
8 if (main_thread) {
9 long int total = 0;
10
21 return 0;
22 }
23
24 #define THREAD_COUNT 10
25
26 int main(void)
27 {
28 thrd_t t[THREAD_COUNT];
29
36 return 0;
37 }
The output will vary from run to run. Notice that even after thrd_yield() other threads might not yet
be ready to run and the main thread will continue.
Main thread yielding
Main thread yielding
Main thread yielding
Other thread running!
Other thread running!
Other thread running!
Other thread running!
Main thread yielding
Other thread running!
Other thread running!
Main thread yielding
Main thread yielding
Main thread yielding
Other thread running!
Main thread yielding
Main thread yielding
66.22. tss_create() 617
See Also
thrd_sleep()
66.22 tss_create()
Create new thread-specific storage
Synopsis
#include <threads.h>
Description
This helps when you need per-thread storage of different values.
A common place this comes up is if you have a file scope variable that is shared between a bunch of
functions and often returned. That’s not threadsafe. One way to refactor is to replace it with thread-
specific storage so that each thread gets their own code and doesn’t step on other thread’s toes.
To make this work, you pass in a pointer to a tss_t key—this is the variable you will use in subsequent
tss_set() and tss_get() calls to set and get the value associated with the key.
The interesting part of this is the dtor destructor pointer of type tss_dtor_t. This is actually a pointer
to a function that takes a void* argument and returns void, i.e.
void dtor(void *p) { ... }
This function will be called per thread when the thread exits with thrd_exit() (or returns from the run
function).
It’s unspecified behavior to call this function while other threads’ destructors are running.
Return Value
Returns nothing!
Example
This is a general-purpose TSS example. Note the TSS variable is created near the top of main().
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
5 tss_t str;
6
7 void some_function(void)
8 {
9 // Retrieve the per-thread value of this string
10 char *tss_string = tss_get(str);
11
618 Chapter 66. <threads.h> Multithreading Functions
12 // And print it
13 printf("TSS string: %s\n", tss_string);
14 }
15
34 #define THREAD_COUNT 15
35
36 int main(void)
37 {
38 thrd_t t[THREAD_COUNT];
39
Output:
TSS string: thread 0! :)
TSS string: thread 2! :)
TSS string: thread 1! :)
TSS string: thread 5! :)
TSS string: thread 3! :)
TSS string: thread 6! :)
TSS string: thread 4! :)
TSS string: thread 7! :)
TSS string: thread 8! :)
TSS string: thread 9! :)
TSS string: thread 10! :)
66.23. tss_delete() 619
See Also
tss_delete(), tss_set(), tss_get(), thrd_exit()
66.23 tss_delete()
Clean up a thread-specific storage variable
Synopsis
#include <threads.h>
Description
This is the opposite of tss_create(). You create (initialize) the TSS variable before using it, then, when
all the threads are done that need it, you delete (deinitialize/free) it with this.
This doesn’t call any destructors! Those are all called by thrd_exit()!
Return Value
Returns nothing!
Example
This is a general-purpose TSS example. Note the TSS variable is deleted near the bottom of main().
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
5 tss_t str;
6
7 void some_function(void)
8 {
9 // Retrieve the per-thread value of this string
10 char *tss_string = tss_get(str);
11
12 // And print it
13 printf("TSS string: %s\n", tss_string);
14 }
15
34 #define THREAD_COUNT 15
35
36 int main(void)
37 {
38 thrd_t t[THREAD_COUNT];
39
Output:
TSS string: thread 0! :)
TSS string: thread 2! :)
TSS string: thread 1! :)
TSS string: thread 5! :)
TSS string: thread 3! :)
TSS string: thread 6! :)
TSS string: thread 4! :)
TSS string: thread 7! :)
TSS string: thread 8! :)
TSS string: thread 9! :)
TSS string: thread 10! :)
TSS string: thread 13! :)
TSS string: thread 12! :)
TSS string: thread 11! :)
TSS string: thread 14! :)
See Also
tss_create(), tss_set(), tss_get(), thrd_exit()
66.24. tss_get() 621
66.24 tss_get()
Get thread-specific data
Synopsis
#include <threads.h>
Description
Once you’ve set a variable with tss_set(), you can retrieve the value with tss_get()—just pass in the
key and you’ll get a pointer to the value back.
Don’t call this from a destructor.
Return Value
Returns the value stored for the given key, or NULL if there’s trouble.
Example
This is a general-purpose TSS example. Note the TSS variable is retrieved in some_function(), below.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
5 tss_t str;
6
7 void some_function(void)
8 {
9 // Retrieve the per-thread value of this string
10 char *tss_string = tss_get(str); // <-- GET THE VALUE
11
12 // And print it
13 printf("TSS string: %s\n", tss_string);
14 }
15
34 #define THREAD_COUNT 15
622 Chapter 66. <threads.h> Multithreading Functions
35
36 int main(void)
37 {
38 thrd_t t[THREAD_COUNT];
39
Output:
TSS string: thread 0! :)
TSS string: thread 2! :)
TSS string: thread 1! :)
TSS string: thread 5! :)
TSS string: thread 3! :)
TSS string: thread 6! :)
TSS string: thread 4! :)
TSS string: thread 7! :)
TSS string: thread 8! :)
TSS string: thread 9! :)
TSS string: thread 10! :)
TSS string: thread 13! :)
TSS string: thread 12! :)
TSS string: thread 11! :)
TSS string: thread 14! :)
See Also
tss_set()
66.25 tss_set()
Set thread-specific data
Synopsis
#include <threads.h>
Description
Once you’ve set up your TSS variable with tss_create(), you can set it on a per thread basis with
tss_set().
key is the identifier for this data, and val is a pointer to it.
The destructor specified in tss_create() will be called for the value set when the thread exits.
Also, if there’s a destructor and there is already at value for this key in place, the destructor will not be
called for the already-existing value. In fact, this function will never cause a destructor to be called. So
you’re on your own, there—best clean up the old value before overwriting it with the new one.
Return Value
Returns thrd_success when happy, and thrd_error when not.
Example
This is a general-purpose TSS example. Note the TSS variable is set in run(), below.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <threads.h>
4
5 tss_t str;
6
7 void some_function(void)
8 {
9 // Retrieve the per-thread value of this string
10 char *tss_string = tss_get(str);
11
12 // And print it
13 printf("TSS string: %s\n", tss_string);
14 }
15
34 #define THREAD_COUNT 15
35
36 int main(void)
37 {
38 thrd_t t[THREAD_COUNT];
39
41 tss_create(&str, free);
42
Output:
TSS string: thread 0! :)
TSS string: thread 2! :)
TSS string: thread 1! :)
TSS string: thread 5! :)
TSS string: thread 3! :)
TSS string: thread 6! :)
TSS string: thread 4! :)
TSS string: thread 7! :)
TSS string: thread 8! :)
TSS string: thread 9! :)
TSS string: thread 10! :)
TSS string: thread 13! :)
TSS string: thread 12! :)
TSS string: thread 11! :)
TSS string: thread 14! :)
See Also
tss_get()
Chapter 67
Function Description
clock() How much processor time has been used by this process
difftime() Compute the difference between two times
mktime() Convert a struct tm into a time_t
time() Get the current calendar time
timespec_get() Get a higher resolution time, probably now
asctime() Return a human-readable version of a struct tm
ctime() Return a human-readable version of a time_t
gmtime() Convert a calendar time into a UTC broken-down time
localtime() Convert a calendar time into a broken-down local time
strftime() Formatted date and time output
When it comes to time and C, there are two main types to look for:
• time_t holds a calendar time. This is an potentially opaque numeric type that represents an absolute
time that can be converted to UTC1 or local time.
• struct tm holds a broken-down time. This has things like the day of the week, the day of the
month, the hour, the minute, the second, etc.
On POSIX systems and Windows, time_t is an integer and represents the number of seconds that have
elapsed since January 1, 1970 at 00:00 UTC.
A struct tm contains the following fields:
struct tm {
int tm_sec; // seconds after the minute -- [0, 60]
int tm_min; // minutes after the hour -- [0, 59]
int tm_hour; // hours since midnight -- [0, 23]
int tm_mday; // day of the month -- [1, 31]
int tm_mon; // months since January -- [0, 11]
int tm_year; // years since 1900
int tm_wday; // days since Sunday -- [0, 6]
int tm_yday; // days since January 1 -- [0, 365]
int tm_isdst; // Daylight Saving Time flag
};
You can convert between the two with mktime(), gmtime(), and localtime().
You can print time information to strings with ctime(), asctime(), and strftime().
1
When you say GMT, unless you’re talking specifically about the time zone and not the time, you probably mean “UTC”.
625
626 Chapter 67. <time.h> Date and Time Functions
67.2 clock()
How much processor time has been used by this process
Synopsis
#include <time.h>
clock_t clock(void);
Description
Your processor is juggling a lot of things right now. Just because a process has been alive for 20 minutes
doesn’t mean that it used 20 minutes of “CPU time”.
Most of the time your average process spends asleep, and that doesn’t count toward the CPU time spent.
This function returns an opaque type representing the number of “clock ticks”2 the process has spent in
operation.
You can get the number of seconds out of that by dividing by the macro CLOCKS_PER_SEC. This is an
integer, so you will have to cast part of the expression to a floating type to get a fractional time.
Note that this is not the “wall clock time” of the program. If you want to get that loosely use time() and
difftime() (which might only offer 1-second resolution) or timespec_get() (which might only also
offer low resolution, but at least it might go to nanosecond level).
Return Value
Returns the amount of CPU time spent by this process. This comes back in a form that can be divided by
CLOCKS_PER_SEC to determine the time in seconds.
Example
1 #include <stdio.h>
2 #include <time.h>
3
2
The spec doesn’t actually say “clock ticks”, but I… am.
67.3. difftime() 627
10
11 int main(void)
12 {
13 printf("The 42nd Fibonacci Number is %lld\n", fib(42));
14
Output on my system:
The 42nd Fibonacci Number is 267914296
CPU time: 1.863078
See Also
time(), difftime(), timespec_get()
67.3 difftime()
Compute the difference between two times
Synopsis
#include <time.h>
Description
Since the time_t type is technically opaque, you can’t just straight-up subtract to get the difference
between two of them3 . Use this function to do it.
There is no guarantee as to the resolution of this difference, but it’s probably to the second.
Return Value
Returns the difference between two time_ts in seconds.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 // April 12, 1982 and change
7 struct tm time_a = { .tm_year=82, .tm_mon=3, .tm_mday=12,
8 .tm_hour=4, .tm_min=00, .tm_sec=04, .tm_isdst=-1,
9 };
10
3
Unless you’re on a POSIX system where time_t is definitely an integer, in which case you can subtract. But you should still
use difftime() for maximum portability.
628 Chapter 67. <time.h> Date and Time Functions
15
Output:
1217996816.000000 seconds (38.596783 years) between events
See Also
time(), mktime()
67.4 mktime()
Convert a struct tm into a time_t
Synopsis
#include <time.h>
Description
If you have a local date and time and want it converted to a time_t (so that you can difftime() it or
whatever), you can convert it with this function.
Basically you fill out the fields in your struct tm in local time and mktime() will convert those to the
UTC time_t equivalent.
A couple notes:
• Don’t bother filling out tm_wday or tm_yday. mktime() will fill these out for you.
• You can set tm_isdst to 0 to indicate your time isn’t Daylight Saving Time (DST), 1 to indicate it
is, and -1 to have mktime() fill it in according to your locale’s preference.
If you need input in UTC, see the non-standard functions timegm()4 for Unix-likes and _mkgmtime()5
for Windows.
Return Value
Returns the local time in the struct tm as a time_t calendar time.
Example
In the following example, we have mktime() tell us if that time was DST or not.
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 struct tm broken_down_time = {
7 .tm_year=82, // years since 1900
8 .tm_mon=3, // months since January -- [0, 11]
9 .tm_mday=12, // day of the month -- [1, 31]
10 .tm_hour=4, // hours since midnight -- [0, 23]
11 .tm_min=00, // minutes after the hour -- [0, 59]
12 .tm_sec=04, // seconds after the minute -- [0, 60]
13 .tm_isdst=-1, // Daylight Saving Time flag
14 };
15
See Also
localtime(), gmtime()
67.5 time()
Get the current calendar time
Synopsis
#include <time.h>
Description
Returns the current calendar time right now. I mean, now. No, now!
If timer is not NULL, it gets loaded with the current time, as well.
This can be converted into a struct tm with localtime() or gmtime(), or printed directly with
ctime().
Return Value
Returns the current calendar time. Also loads timer with the current time if it’s not NULL.
Or returns (time_t)(-1) if the time isn’t available because you’ve fallen out of the space-time continuum
and/or the system doesn’t support times.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 time_t now = time(NULL);
7
Example output:
The local time is Mon Mar 1 18:45:14 2021
See Also
localtime(), gmtime(), ctime()
67.6 timespec_get()
Get a higher resolution time, probably now
Synopsis
#include <time.h>
Description
This function loads the current time UTC (unless directed otherwise) into the given struct timespec,
ts.
Nanoseconds are billionths of a second. You can divide by 1000000000.0 to convert to seconds.
The base parameter has only one defined value, by the spec: TIME_UTC. So portably make it that. This
will load ts with the current time in seconds since a system-defined Epoch6 , often January 1, 1970 at
00:00 UTC.
Your implementation might define other values for base.
Return Value
When base is TIME_UTC, loads ts with the current UTC time.
On success, returns base, valid values for which will always be non-zero. On error, returns 0.
Example
1 struct timespec ts;
2
3 timespec_get(&ts, TIME_UTC);
4
Example output:
1614654187 s, 825540756 ns
1614654187.825541 seconds since epoch
Here’s a helper function to add values to a struct timespec that handles negative values and nanosecond
overflow.
#include <stdlib.h>
if (qr.rem < 0) {
nsec = 1000000000L + qr.rem;
sec += qr.quot - 1;
} else {
nsec = qr.rem;
sec += qr.quot;
}
ts->tv_sec = sec;
ts->tv_nsec = nsec;
6
https://en.wikipedia.org/wiki/Unix_time
632 Chapter 67. <time.h> Date and Time Functions
return ts;
}
And here are some functions to convert from long double to struct timespec and back, just in case
you like thinking in decimals. This is more limited in significant figures than using the integer values.
#include <math.h>
return ts;
}
See Also
time(), mtx_timedlock(), cnd_timedwait()
67.7 asctime()
Return a human-readable version of a struct tm
Synopsis
#include <time.h>
Description
This takes a time in a struct tm and returns a string with that date in the form:
Sun Sep 16 01:03:52 1973
with a newline included at the end, rather unhelpfully. (strftime() will give you more flexibility.)
It’s just like ctime(), except it takes a struct tm instead of a time_t.
WARNING: This function returns a pointer to a static char* region that isn’t thread-safe and might be
shared with the ctime() function. If you need thread safety, use strftime() or use a mutex that covers
ctime() and asctime().
Return Value
Returns a pointer to the human-readable date string.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 time_t now = time(NULL);
7
Sample output:
Local: Mon Mar 1 21:17:34 2021
UTC : Tue Mar 2 05:17:34 2021
See Also
ctime(), localtime(), gmtime()
67.8 ctime()
Return a human-readable version of a time_t
Synopsis
#include <time.h>
Description
This takes a time in a time_t and returns a string with the local time and date in the form:
Sun Sep 16 01:03:52 1973
with a newline included at the end, rather unhelpfully. (strftime() will give you more flexibility.)
It’s just like asctime(), except it takes a time_t instead of a struct tm.
WARNING: This function returns a pointer to a static char* region that isn’t thread-safe and might
be shared with the asctime() function. If you need thread safety, use strftime() or use a mutex that
covers ctime() and asctime().
Behavior is undefined for:
• Years less than 1000
• Years greater than 9999
• Any members of timeptr are out of range
Return Value
A pointer to the human-readable local time and data string.
634 Chapter 67. <time.h> Date and Time Functions
Example
1 time_t now = time(NULL);
2
Sample output:
Local: Mon Mar 1 21:32:23 2021
See Also
asctime()
67.9 gmtime()
Convert a calendar time into a UTC broken-down time
Synopsis
#include <time.h>
Description
If you have a time_t, you can run it through this function to get a struct tm back full of the correspond-
ing broken-down UTC time information.
This is just like localtime(), except it does UTC instead of local time.
Once you have that struct tm, you can feed it to strftime() to print it out.
WARNING: This function returns a pointer to a static struct tm* region that isn’t thread-safe and
might be shared with the localtime() function. If you need thread safety use a mutex that covers
gmtime() and localtime().
Return Value
Returns a pointer to the broken-down UTC time, or NULL if it can’t be obtained.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 time_t now = time(NULL);
7
Sample output:
UTC : Tue Mar 2 05:40:05 2021
Local: Mon Mar 1 21:40:05 2021
67.10. localtime() 635
See Also
localtime(), asctime(), strftime()
67.10 localtime()
Convert a calendar time into a broken-down local time
Synopsis
#include <time.h>
Description
If you have a time_t, you can run it through this function to get a struct tm back full of the correspond-
ing broken-down local time information.
This is just like gmtime(), except it does local time instead of UTC.
Once you have that struct tm, you can feed it to strftime() to print it out.
WARNING: This function returns a pointer to a static struct tm* region that isn’t thread-safe and
might be shared with the gmtime() function. If you need thread safety use a mutex that covers gmtime()
and localtime().
Return Value
Returns a pointer to the broken-down local time, or NULL if it can’t be obtained.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 time_t now = time(NULL);
7
Sample output:
Local: Mon Mar 1 21:40:05 2021
UTC : Tue Mar 2 05:40:05 2021
See Also
gmtime(), asctime(), strftime()
67.11 strftime()
Formatted date and time output
636 Chapter 67. <time.h> Date and Time Functions
Synopsis
#include <time.h>
Description
This is the sprintf() of date and time functions. It’ll take a struct tm and produce a string in just
about whatever form you desire, for example:
2021-03-01
Monday, March 1 at 9:54 PM
It's Monday!
It’s a super flexible version of asctime(). And thread-safe, besides, since it doesn’t rely on a static buffer
to hold the results.
Basically what you do is give it a destination, s, and its max size in bytes in maxsize. Also, provide a
format string that’s analogous to printf()’s format string, but with different format specifiers. And
lastly, a struct tm with the broken-down time information to use for printing.
The format string works like this, for example:
"It's %A, %B %d!"
Which produces:
It's Monday, March 1!
The %A is the full day-of-week name, the %B is the full month name, and the %d is the day of the month.
strftime() substitutes the right thing to produce the result. Brilliant!
Specifier Description
%a Locale’s abbreviated weekday name. [tm_wday]
%A Locale’s full weekday name. [tm_wday]
%b Locale’s abbreviated month name. [tm_mon]
%B Locale’s full month name. [tm_mon]
%c Locale’s appropriate date and time representation.
%C Year divided by 100 and truncated to an integer, as a decimal number (00–99). [tm_year]
%d Day of the month as a decimal number (01–31). [tm_mday]
%D Equivalent to "%m/%d/%y". [tm_mon, tm_mday, tm_year]
%e Day of the month as a decimal number (1–31); a single digit is preceded by a space.
[tm_mday]
%F Equivalent to “%Y-%m-%d” (the ISO 8601 date format). [tm_year, tm_mon, tm_mday]
%g Last 2 digits of the week-based year (see below) as a decimal number (00–99). [tm_year,
tm_wday, tm_yday]
%G Week-based year (see below) as a decimal number (e.g., 1997). [tm_year, tm_wday,
tm_yday]
%h Equivalent to “%b”. [tm_mon]
%H Hour (24-hour clock) as a decimal number (00–23). [tm_hour]
%I Hour (12-hour clock) as a decimal number (01–12). [tm_hour]
%j Day of the year as a decimal number (001–366). [tm_yday]
%m Month as a decimal number (01–12).
%M Minute as a decimal number (00–59). [tm_min]
%n A new-line character.
67.11. strftime() 637
Specifier Description
%p Locale’s equivalent of the AM/PM designations associated with a 12-hour clock.
[tm_hour]
%r Locale’s 12-hour clock time. [tm_hour, tm_min, tm_sec]
%R Equivalent to "%H:%M". [tm_hour, tm_min]
%S Second as a decimal number (00–60). [tm_sec]
%t A horizontal-tab character.
%T Equivalent to "%H:%M:%S" (the ISO 8601 time format). [tm_hour, tm_min, tm_sec]
%u ISO 8601 weekday as a decimal number (1–7), where Monday is 1. [tm_wday]
%U Week number of the year (the first Sunday as the first day of week 1) as a decimal number
(00–53). [tm_year, tm_wday, tm_yday]
%V ISO 8601 week number (see below) as a decimal number (01–53). [tm_year, tm_wday,
tm_yday]
%w Weekday as a decimal number (0–6), where Sunday is 0.
%W Week number of the year (the first Monday as the first day of week 1) as a decimal number
(00–53). [tm_year, tm_wday, tm_yday]
%x Locale’s appropriate date representation.
%X Locale’s appropriate time representation.
%y Last 2 digits of the year as a decimal number (00–99). [tm_year]
%Y Year as a decimal number (e.g., 1997). [tm_year]
%z Offset from UTC in the ISO 8601 format "-0430" (meaning 4 hours 30 minutes behind
UTC, west of Greenwich), or by no characters if no time zone is determinable. [tm_isdst]
%Z Locale’s time zone name or abbreviation, or by no characters if no time zone is
determinable. [tm_isdst]
%% A plain ol’ %
Specifier Description
%a The first three characters of %A.
%A One of Sunday, Monday, … , Saturday.
%b The first three characters of %B.
%B One of January, February, … , December.
%c Equivalent to %a %b %e %T %Y.
%p One of AM or PM.
%r Equivalent to %I:%M:%S %p.
%x Equivalent to %m/%d/%y.
%X Equivalent to %T.
%Z Implementation-defined.
7
https://en.wikipedia.org/wiki/ISO_week_date
638 Chapter 67. <time.h> Date and Time Functions
There are additional variants of the format specifiers that indicate you want to use a locale’s alternative
format. These don’t exist for all locales. It’s one of the format specifies above, with either an E or O prefix:
%Ec %EC %Ex %EX %Ey %EY %Od %Oe %OH %OI
%Om %OM %OS %Ou %OU %OV %Ow %OW %Oy
Return Value
Returns the total number of bytes put into the result string, not including the NUL terminator.
If the result doesn’t fit in the string, zero is returned and the value in s is indeterminate.
Example
1 #include <stdio.h>
2 #include <time.h>
3
4 int main(void)
5 {
6 char s[128];
7 time_t now = time(NULL);
8
See Also
ctime(), asctime()
Chapter 68
Function Description
c16rtomb() Convert a char16_t to a multibyte character
c32rtomb() Convert a char32_t to a multibyte character
mbrtoc16() Convert a multibyte character to a char16_t
mbrtoc32() Convert a multibyte character to a char32_t
These functions are restartable, meaning multiple threads can safely call them at once. They handle this
by having their own conversion state variable (of type mbstate_t) per call.
68.1 Types
This header file defines four types.
Type Description
char16_t Type to hold 16-bit characters
char32_t Type to hold 32-bit characters
mbstate_t Holds the conversion state for restartable funcitons (also defined in <wchar.h>)
size_t To hold various counts (also defined in <stddef.h>)
String literals for the character types are u for char16_t and U for char32_t.
char16_t *str1 = u"Hello, world!";
char32_t *str2 = U"Hello, world!";
Note that char16_t and char32_t might contain Unicode. Or not. If __STDC_UTF_16__ or
__STDC_UTF_32__ is defined as 1, then char16_t and char32_t use Unicode, respectively. Otherwise
they don’t and the actual value stored depend on the locale. And if you’re not using Unicode, you have
my commiserations.
68.2 OS X issue
This header file doesn’t exist on OS X—bummer. If you just want the types, you can:
639
640 Chapter 68. <uchar.h> Unicode utility functions
#include <stdint.h>
Synopsis
#include <uchar.h>
Description
Given a source string s and a destination buffer pc16 (or pc32 for mbrtoc32()), convert the first character
of the source to char16_ts (or char32_ts for mbrtoc32()).
Basically you have a regular character and you want it as char16_t or char32_t. Use these functions to
do it. Note that only one character is converted no matter how many characters in s.
As the functions scan s, you don’t want them to overrun the end. So you pass in n as the maximum number
of bytes to inspect. The functions will quit after that many bytes or when they have a complete multibyte
character, whichever comes first.
Since they’re restartable, pass in a conversion state variable for the functions to do their work.
And the result will be placed in pc16 (or pc32 for mbrtoc32()).
Return Value
When successful this function returns a number between 1 and n inclusive representing the number of
bytes that made up the multibyte character.
Or, also in the success category, they can return 0 if the source character is the NUL character (value 0).
When not entirely successful, they can return a variety of codes. These are all of type size_t, but negative
values cast to that type.
Case (size_t)(-3) is an odd one. Basically there are some characters that can’t be represented with 16
bits and so can’t be stored in a char16_t. These characters are store in something called (in the Unicode
68.3. mbrtoc16() mbrtoc32() 641
world) surrogate pairs. That is, there are two 16-bit values back to back that represent a larger Unicode
value.
For example, if you want to read the Unicode character \U0001fbc5 (which is a stick figure1 —I’m just
not putting it in the text because my font doesn’t render it) that’s more than 16 bits. But each call to
mbrtoc16() only returns a single char16_t!
So subsequent calls to mbrtoc16() resolves the next value in the surrogate pair and returns (size_t)(-
3) to let you know this has happened.
You can also pass NULL for pc16 or pc32. This will cause no result to be stored, but you can use it if
you’re only interested in the return value from the functions.
Finally, if you pass NULL for s, the call is equivalent to:
mbrtoc16(NULL, "", 1, ps)
Since the character is a NUL in that case, this has the effect of setting the state in ps to the initial conversion
state.
Example
Normal use case example where we get the first two character values from the multibyte string "€Zil-
lion":
#include <uchar.h>
#include <stdio.h> // for printf()
#include <locale.h> // for setlocale()
#include <string.h> // for memset()
int main(void)
{
char *s = "\u20acZillion"; // 20ac is "€"
char16_t pc16;
size_t r;
mbstate_t mbs;
setlocale(LC_ALL, "");
memset(&mbs, 0, sizeof mbs);
Example with a surrogate pair. In this case we read plenty to get the entire character, but the result must
be stored in two char16_ts, requiring two calls to get them both.
1 #include <uchar.h>
2 #include <stdio.h> // for printf()
3 #include <string.h> // for memset()
1
https://en.wikipedia.org/wiki/Symbols_for_Legacy_Computing
642 Chapter 68. <uchar.h> Unicode utility functions
6 int main(void)
7 {
8 char *s = "\U0001fbc5*"; // Stick figure glyph, more than 16 bits
9 char16_t pc16;
10 mbstate_t mbs;
11 size_t r;
12
13 setlocale(LC_ALL, "");
14 memset(&mbs, 0, sizeof mbs);
15
16 r = mbrtoc16(&pc16, s, 8, &mbs);
17
23 r = mbrtoc16(&pc16, s, 8, &mbs);
24
32 r = mbrtoc16(&pc16, s, 8, &mbs);
33
Output on my system, indicating the first character is represented by the pair (0xd83e, 0xdfc5) and the
second character is represented by 0x2a:
4
0xd83e
-3
0xdfc5
1
0x2a
See Also
c16rtomb(), c32rtomb()
Synopsis
#include <uchar.h>
68.4. c16rtomb() c32rtomb() 643
Description
If you have a character in a char16_t or char32_t, use these functions to convert them into a multibyte
character.
These functions figure out how many bytes are needed for the multibyte character in the current locale
and stores them in the buffer pointed to by s.
But how big to make that buffer? Luckily there is a macro to help: it needs be no larger than MB_CUR_MAX.
As a special case, if s is NULL, it’s the same as calling
c16rtomb(buf, L'\0', ps); // or...
c32rtomb(buf, L'\0', ps);
where buf is a buffer maintained by the system that you don’t have access to.
This has the effect of setting the ps state to the initial state.
Finally for surrogate pairs (where the character has been split into two char16_ts), you call this once
with the first of the pair—at this point, the function will return 0. Then you call it again with the second
of the pair, and the function will return the number of bytes and store the result in the array s.
Return Value
Returns the number of bytes stored in the array pointed to by s.
Returns 0 if processing is not yet complete for the current character, as in the case of surrogate pairs.
If there is an encoding error, the functions return (size_t)(-1) and errno is set to EILSEQ.
Example
1 #include <uchar.h>
2 #include <stdlib.h> // for MB_CUR_MAX
3 #include <stdio.h> // for printf()
4 #include <string.h> // for memset()
5 #include <locale.h> // for setlocale()
6
7 int main(void)
8 {
9 char16_t c16 = 0x20ac; // Unicode for Euro symbol
10 char dest[MB_CUR_MAX];
11 size_t r;
12 mbstate_t mbs;
13
14 setlocale(LC_ALL, "");
15 memset(&mbs, 0, sizeof mbs); // Reset conversion state
16
17 // Convert
18 r = c16rtomb(dest, c16, &mbs);
19
Output on my system:
r == 3
dest == "€"
This is a more complex example that converts a large-valued character in a multibyte string into a surrogate
pair (as in the mbrtoc16() example, above) and then converts it back again into a multibyte string to print.
1 #include <uchar.h>
2 #include <stdlib.h> // for MB_CUR_MAX
3 #include <stdio.h> // for printf()
4 #include <string.h> // for memset()
5 #include <locale.h> // for setlocale()
6
7 int main(void)
8 {
9 char *src = "\U0001fbc5*"; // Stick figure glyph, more than 16 bits
10 char dest[MB_CUR_MAX];
11 char16_t surrogate0, surrogate1;
12 mbstate_t mbs;
13 size_t r;
14
15 setlocale(LC_ALL, "");
16 memset(&mbs, 0, sizeof mbs); // Reset conversion state
17
27 // Now reverse it
28 memset(&mbs, 0, sizeof mbs); // Reset conversion state
29
See Also
mbrtoc16(), mbrtoc32()
Chapter 69
Function Description
btowc() Convert a single byte character to a wide character
fgetwc() Get a wide character from a wide stream
fgetws() Read a wide string from a wide stream
fputwc() Write a wide character to a wide stream
fputws() Write a wide string to a wide stream
fwide() Get or set the orientation of the stream
fwprintf() Formatted wide output to a wide stream
fwscanf() Formatted wide input from a wide stream
getwchar() Get a wide character from stdin
getwc() Get a wide character from stdin
mbrlen() Compute the number of bytes in a multibyte character restartably
mbrtowc() Convert multibyte to wide characters restartably
mbsinit() Test if an mbstate_t is in the initial conversion state
mbsrtowcs() Convert a multibyte string to a wide character string restartably
putwchar() Write a wide character to stdout
putwc() Write a wide character to stdout
swprintf() Formatted wide output to a wide string
swscanf() Formatted wide input from a wide string
ungetwc() Pushes a wide character back into the input stream
vfwprintf() Variadic formatted wide output to a wide stream
vfwscanf() Variadic formatted wide input from a wide stream
vswprintf() Variadic formatted wide output to a wide string
vswscanf() Variadic formatted wide input from a wide string
vwprintf() Variadic formatted wide output
vwscanf() Variadic formatted wide input
wcscat() Concatenate wide strings dangerously
wcschr() Find a wide character in a wide string
wcscmp() Compare wide strings
wcscoll() Compare two wide strings accounting for locale
wcscpy() Copy a wide string dangerously
wcscspn() Count characters not from a start at the front of a wide string
wcsftime() Formatted date and time output
wcslen() Returns the length of a wide string
wcsncat() Concatenate wide strings more safely
wcsncmp() Compare wide strings, length limited
wcsncpy() Copy a wide string more safely
wcspbrk() Search a wide string for one of a set of wide characters
wcsrchr() Find a wide character in a wide string from the end
wcsrtombs() Convert a wide character string to a multibyte string restartably
645
646 Chapter 69. <wchar.h> Wide Character Handling
Function Description
wcsspn() Count characters from a set at the front of a wide string
wcsstr() Find a wide string in another wide string
wcstod() Convert a wide string to a double
wcstof() Convert a wide string to a float
wcstok() Tokenize a wide string
wcstold() Convert a wide string to a long double
wcstoll() Convert a wide string to a long long
wcstol() Convert a wide string to a long
wcstoull() Convert a wide string to an unsigned long long
wcstoul() Convert a wide string to an unsigned long
wcsxfrm() Transform a wide string for comparing based on locale
wctob() Convert a wide character to a single byte character
wctombr() Convert wide to multibyte characters restartably
wmemcmp() Compare wide characters in memory
wmemcpy() Copy wide character memory
wmemmove() Copy wide character memory, potentially overlapping
wprintf() Formatted wide output
wscanf() Formatted wide input
These are the wide character variants of the functions found in <stdio.h>.
Remember that you can’t mix-and-match multibyte output functions (like printf()) with wide character
output functions (like wprintf()). The output stream has an orientation to either multibyte or wide that
gets set on the first I/O call to that stream. (Or it can be set with fwide().)
So choose one or the other and stick with it.
And you can specify wide character constants and string literals by prefixing L to the front of it:
wchar_t *s = L"Hello, world!";
wchar_t c = L'B';
This header also introduces a type wint_t that is used by the character I/O functions. It’s a type that can
hold any single wide character, but also the macro WEOF to indicate wide end-of-file.
Synopsis
#include <stdio.h> // For fwprintf()
#include <wchar.h>
69.3. wscanf() fwscanf() swscanf() 647
Description
These are the wide versions of printf(), fprintf()](#man-printf), and [sprintf()‘.
See those pages for exact substantial usage.
These are the same except the format string is a wide character string instead of a multibyte string.
And that swprintf() is analogous to snprintf() in that they both take the size of the destination array
as an argument.
And one more thing: the precision specified for a %s specifier corresponds to the number of wide characters
printed, not the number of bytes. If you know of other difference, let me know.
Return Value
Returns the number of wide characters outputted, or -1 if there’s an error.
Example
1 #include <stdio.h>
2 #include <wchar.h>
3
4 int main(void)
5 {
6 char *mbs = "multibyte";
7 wchar_t *ws = L"wide";
8
11 double pi = 3.14159265358979;
12 wprintf(L"pi = %f\n", pi);
13 }
Output:
We're all wide for multibyte and wide!
pi = 3.141593
See Also
printf(), vwprintf()
Synopsis
648 Chapter 69. <wchar.h> Wide Character Handling
Description
These are the wide variants of scanf(), fscanf(), and sscanf().
See the scanf() page for all the details.
Return Value
Returns the number of items successfully scanned, or EOF on some kind of input failure.
Example
1 #include <stdio.h>
2 #include <wchar.h>
3
4 int main(void)
5 {
6 int quantity;
7 wchar_t item[100];
8
See Also
scanf(), vwscanf()
Synopsis
#include <stdio.h> // For vfwprintf()
#include <stdarg.h>
69.4. vwprintf() vfwprintf() vswprintf() 649
#include <wchar.h>
Description
These functions are the wide character variants of the vprintf(), functions. You can refer to that refer-
ence page for more details.
Return Value
Returns the number of wide characters stored, or a negative value on error.
Example
In this example, we make our own version of wprintf() called wlogger() that timestamps output. No-
tice how the calls to wlogger() have all the bells and whistles of wprintf().
1 #include <stdarg.h>
2 #include <wchar.h>
3 #include <time.h>
4
16 va_start(va, format);
17 int result = vwprintf(format, va);
18 va_end(va);
19
20 wprintf(L"\n");
21
22 return result;
23 }
24
25 int main(void)
26 {
27 int x = 12;
28 float y = 3.2;
29
30 wlogger(L"Hello!");
31 wlogger(L"x = %d and y = %.2f", x, y);
32 }
Output:
650 Chapter 69. <wchar.h> Wide Character Handling
See Also
printf(), vprintf()
Synopsis
#include <stdio.h> // For vfwscanf()
#include <stdarg.h>
#include <wchar.h>
Description
These are the wide counterparts to the vscanf() collection of functions. See their reference page for
details.
Return Value
Returns the number of items successfully scanned, or EOF on some kind of input failure.
Example
I have to admit I was wracking my brain to think of when you’d ever want to use this. The best example
I could find was one on Stack Overflow1 that error-checks the return value from scanf() against the
expected. A variant of that is shown below.
1 #include <stdarg.h>
2 #include <wchar.h>
3 #include <assert.h>
4
9 va_start(va, format);
10 int count = vwscanf(format, va);
11 va_end(va);
12
1
https://stackoverflow.com/questions/17017331/c99-vscanf-for-dummies/17018046#17018046
69.6. getwc() fgetwc() getwchar() 651
15
16 return count;
17 }
18
19 int main(void)
20 {
21 int a, b;
22 float c;
23
See Also
wscanf()
Synopsis
#include <stdio.h> // For getwc() and fgetwc()
#include <wchar.h>
wint_t getwchar(void);
Description
These are the wide variants of fgetc().
fgetwc() and getwc() are identical except that getwc() might be implemented as a macro and is al-
lowed to evaluate stream multiple times.
getwchar() is identical to getwc() with stream set to stdin.
I don’t know why you’d ever use getwc() instead of fgetwc(), but if anyone knows, drop me a line.
Return Value
Returns the next wide character in the input stream. Return WEOF on end-of-file or error.
If an I/O error occurs, the error flag is also set on the stream.
If an invalid byte sequence is encountered, errno is set to ILSEQ.
Example
Reads all the characters from a file, outputting only the letter ’b’s it finds in the file:
1 #include <stdio.h>
2 #include <wchar.h>
3
652 Chapter 69. <wchar.h> Wide Character Handling
4 int main(void)
5 {
6 FILE *fp;
7 wint_t c;
8
17 fclose(fp);
18 }
See Also
fputwc, fgetws, errno
69.7 fgetws()
Read a wide string from a file
Synopsis
#include <stdio.h>
#include <wchar.h>
Description
This is the wide version of fgets(). See its reference page for details.
A wide NUL character is used to terminate the string.
Return Value
Returns s on success, or a NULL pointer on end-of-file or error.
Example
The following example reads lines from a file and prepends them with numbers:
1 #include <stdio.h>
2 #include <wchar.h>
3
6 int main(void)
7 {
8 FILE *fp;
9 wchar_t buf[BUF_SIZE];
10
12
13 int line_count = 0;
14
18 fclose(fp);
19 }
Example output for a file with these lines in them (without the prepended numbers):
0001: line 1
0002: line 2
0003: something
0004: line 4
See Also
fgetwc(), fgets()
Synopsis
#include <stdio.h> // For putwc() and fputwc()
#include <wchar.h>
Description
These are the wide character equivalents to the ‘fputc()’ group of functions. You can find more information
‘in that reference section’.
fputwc() and putwc() are identical except that putwc() might be implemented as a macro and is al-
lowed to evaluate stream multiple times.
putwchar() is identical to putwc() with stream set to stdin.
I don’t know why you’d ever use putwc() instead of fputwc(), but if anyone knows, drop me a line.
Return Value
Returns the wide character written, or WEOF on error.
If it’s an I/O error, the error flag will be set for the stream.
If it’s an encoding error, errno will be set to EILSEQ.
Example
Read all characters from a file, outputting only the letter ’b’s it finds in the file:
654 Chapter 69. <wchar.h> Wide Character Handling
1 #include <stdio.h>
2 #include <wchar.h>
3
4 int main(void)
5 {
6 FILE *fp;
7 wint_t c;
8
17 fclose(fp);
18 }
See Also
fgetwc(), fputc(), errno
69.9 fputws()
Write a wide string to a file
Synopsis
#include <stdio.h>
#include <wchar.h>
Description
This is the wide version of fputs().
Pass in a wide string and an output stream, and it will so be written.
Return Value
Returns a non-negative value on success, or EOF on error.
Example
1 #include <stdio.h>
2 #include <wchar.h>
3
4 int main(void)
5 {
6 fputws(L"Hello, world!\n", stdout);
7 }
69.10. fwide() 655
See Also
fputwc() fputs()
69.10 fwide()
Get or set the orientation of the stream
Synopsis
#include <stdio.h>
#include <wchar.h>
Description
Streams can be either wide-oriented (meaning the wide functions are in use) or byte-oriented (that the
regular multibyte functions are in use). Or, before an orientation is chosen, unoriented.
There are two ways to set the orientation of an unoriented stream:
• Implicitly: just use a function like printf() (byte oriented) or wprintf() (wide oriented), and
the orientation will be set.
• Explicitly: use this function to set it.
You can set the orientation for the stream by passing different numbers to mode:
mode Description
0 Do not alter the orientation
-1 Set stream to byte-oriented
1 Set stream to wide-oriented
(I said -1 and 1 there, but really it could be any positive or negative number.)
Most people choose the wide or byte functions (printf() or wprintf()) and just start using them and
never use fwide() to set the orientation.
And once the orientation is set, you can’t change it. So you can’t use fwide() for that, either.
So what can you use it for?
You can test to see what orientation a stream is in by passing 0 as the mode and checking the return value.
Return Value
Returns greater than zero if the stream is wide-oriented.
Returns less than zero if the stream is byte-oriented.
Returns zero if the stream is unoriented.
Example
Example setting to byte-oriented:
656 Chapter 69. <wchar.h> Wide Character Handling
1 #include <stdio.h>
2 #include <wchar.h>
3
4 int main(void)
5 {
6 printf("Hello world!\n"); // Implicitly set to byte
7
Output:
Hello world!
Stream is byte-oriented
4 int main(void)
5 {
6 wprintf(L"Hello world!\n"); // Implicitly set to wide
7
Output:
Hello world!
Stream is wide-oriented
69.11 ungetwc()
Pushes a wide character back into the input stream
Synopsis
#include <stdio.h>
#include <wchar.h>
Description
This is the wide character variant of ungetc().
It performs the reverse operation of fgetwc(), pushing a character back on the input stream.
The spec guarantees you can do this one time in a row. You can probably do it more times, but it’s up to
the implementation. If you do too many calls without an intervening read, an error could be returned.
Setting the file position discards any characters pushed by ungetwc() without being subsequently read.
The end-of-file flag is cleared after a successful call.
69.11. ungetwc() 657
Return Value
Returns the value of the pushed character on success, or WEOF on failure.
Example
This example reads a piece of punctuation, then everything after it up to the next piece of punctuation. It
returns the leading punctuation, and stores the rest in a string.
1 #include <stdio.h>
2 #include <wctype.h>
3 #include <wchar.h>
4
9 origpunct = fgetwc(fp);
10
24 return origpunct;
25 }
26
27 int main(void)
28 {
29 wchar_t s[128];
30 wint_t c;
31
Sample Input:
!foo#bar*baz
Sample output:
!: foo
#: bar
*: baz
See Also
fgetwc(), ungetc()
658 Chapter 69. <wchar.h> Wide Character Handling
Synopsis
#include <wchar.h>
Description
These are the wide counterparts to the strtod() family of functions. See their reference pages for details.
Return Value
Returns the string converted to a floating point value.
Returns 0 if there’s no valid number in the string.
On overflow, returns an apporpriately-signed HUGE_VAL, HUGE_VALF. or HUGE_VALL depending on the
return type, and errno is set to ERANGE.
On underflow, returns a number no greater than the smallest normalized positive number, appropriately
signed. The implemention might set errno to ERANGE.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t *inp = L" 123.4567beej";
6 wchar_t *badchar;
7
18 if (*badchar == L'\0')
19 wprintf(L"No bad chars: %f\n", val);
20 else
21 wprintf(L"Found bad chars: %f, %ls\n", val, badchar);
22 }
Output:
Converted string to 123.456700
Encountered bad characters: beej
69.13. wcstol() wcstoll() wcstoul() wcstoull() 659
See Also
wcstol(), strtod(), errno
Synopsis
#include <wchar.h>
Description
These are the wide counterparts to the strtol() family of functions, so see their reference pages for the
details.
Return Value
Returns the integer value of the string.
If nothing can be found, 0 is returned.
If the result is out of range, the value returned is one of LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX,
ULONG_MAX or ULLONG_MAX, as appropriate. And errno is set to ERANGE.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 // All output in decimal (base 10)
6
16 wchar_t *badchar;
17 long int x = wcstol(L" 1234beej", &badchar, 0);
18
Output:
123
123
42
83
291
83
291
Value is 1234
Bad chars at "beej"
See Also
wcstod(), strtol(), errno, wcstoimax(), wcstoumax()
Synopsis
#include <wchar.h>
Description
These are the wide versions of strcpy() and strncpy().
They’ll copy a string up to a wide NUL. Or, in the case of the safer wcsncpy(), until then or until n wide
characters are copied.
If the string in s1 is shorter than n, wcsncpy() will pad s2 with wide NUL characters until the nth wide
character is reached.
Even though wcsncpy() is safer because it will never overrun the end of s2 (assuming you set n correctly),
it’s still unsafe a NUL is not found in s1 in the first n characters. In that case, s2 will not be NUL-
terminated. Always make sure n is greater than the string length of s1!
Return Value
Returns s1.
69.15. wmemcpy() wmemmove() 661
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t *s1 = L"Hello!";
6 wchar_t s2[10];
7
See Also
wmemcpy(), wmemmove() strcpy(), strncpy()
Synopsis
#include <wchar.h>
Description
These are the wide versions of memcpy() and memmove().
They copy n wide characters from s2 to s1.
They’re the same except that wmemmove() is guaranteed to work with overlapping memory regions, and
wmemcpy() is not.
Return Value
Both functions return the pointer s1.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t s[100] = L"Goats";
6 wchar_t t[100];
7
11
Output:
s is "GoGoats"
t is "Goats"
See Also
wcscpy(), wcsncpy(), memcpy(), memmove()
Synopsis
#include <wchar.h>
Description
These are the wide variants of strcat() and strncat().
They concatenate s2 onto the end of s1.
They’re the same except wcsncat() gives you the option to limit the number of wide characters appended.
Note that wcsncat() always adds a NUL terminator to the end, even if n characters were appended. So
be sure to leave room for that.
Return Value
Both functions return the pointer s1.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t dest[30] = L"Hello";
6 wchar_t *src = L", World!";
7 wchar_t numbers[] = L"12345678";
8
11 wcscat(dest, src);
12 wprintf(L"dest after strcat: \"%ls\"\n", dest); // "Hello, world!"
13
69.17. wcscmp(), wcsncmp(), wmemcmp() 663
See Also
strcat(), strncat()
Synopsis
#include <wchar.h>
Description
These are the wide variants of memcmp(), strcmp(), and strncmp().
wcscmp() and wcsncmp() both compare strings until a NUL character.
wcsncmp() also has the additional restriction that it will only compare the first n characters.
The comparison is done against the character value (which might (or might not) be its Unicode code point).
Return Value
Returns zero if both regions are equal.
Returns a negative number if the region pointed to by s1 is less than s2.
Returns a positive number if the region pointed to by s1 is greater than s2.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t *s1 = L"Muffin";
6 wchar_t *s2 = L"Muffin Sandwich";
7 wchar_t *s3 = L"Muffin";
8
12 if (wcscmp(s1, s2) == 0)
13 wprintf(L"This won't get printed because the strings differ\n");
664 Chapter 69. <wchar.h> Wide Character Handling
14
15 if (wcscmp(s1, s3) == 0)
16 wprintf(L"This will print because s1 and s3 are the same\n");
17
24 if (!wcscmp(s1, s3))
25 wprintf(L"The strings are the same!\n");
26
Output:
-1
1
This will print because s1 and s3 are the same
The strings are the same!
The first 6 characters of s1 and s2 are the same
See Also
wcscoll(), memcmp(), strcmp(), strncmp()
69.18 wcscoll()
Compare two wide strings accounting for locale
Synopsis
#include <wchar.h>
Description
This is the wide version of strcoll(). See that reference page for details.
This is slower than wcscmp(), so only use it if you need the locale-specific compare.
Return Value
Returns zero if both regions are equal in this locale.
Returns a negative number if the region pointed to by s1 is less than s2 in this locale.
Returns a positive number if the region pointed to by s1 is greater than s2 in this locale.
Example
1 #include <wchar.h>
2 #include <locale.h>
69.19. wcsxfrm() 665
4 int main(void)
5 {
6 setlocale(LC_ALL, "");
7
See Also
wcscmp(), wcsxfrm(), strcoll()
69.19 wcsxfrm()
Transform a wide string for comparing based on locale
Synopsis
#include <wchar.h>
Description
This is the wide variant of strxfrm(). See that reference page for details.
Return Value
Returns the length of the transformed wide string in wide characters.
If the return value is greater than n, all bets are off for the result in s1.
Example
1 #include <wchar.h>
2 #include <locale.h>
3 #include <stdlib.h>
4
12 wcsxfrm(d, s, len);
13
14 return d;
15 }
666 Chapter 69. <wchar.h> Wide Character Handling
16
25 free(s1_transformed);
26
27 return result;
28 }
29
30 int main(void)
31 {
32 setlocale(LC_ALL, "");
33
42 free(s);
43 }
Output:
1
-1
1
See Also
wcscmp(), wcscoll(), strxfrm()
Synopsis
#include <wchar.h>
Description
These are the wide equivalents to strchr(), strrchr(), and memchr().
69.21. wcsspn() wcscspn() 667
They search for wide characters in a wide string from the front (wcschr()), the end (wcsrchr()) or for
an arbitrary number of wide characters (wmemchr()).
Return Value
All three functions return a pointer to the wide character found, or NULL if the character, sadly, isn’t found.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 // "Hello, world!"
6 // ^ ^ ^
7 // A B C
8
Output:
Found a 'B' here: BIG BROWN BAT BIT BEEJ
Found a 'B' here: BROWN BAT BIT BEEJ
Found a 'B' here: BAT BIT BEEJ
Found a 'B' here: BIT BEEJ
Found a 'B' here: BEEJ
See Also
strchr(), strrchr(), memchr()
Synopsis
#include <wchar.h>
Description
The are the wide character counterparts to [strspn()] (#man-strspn)and strcspn().
They compute the length of the string pointed to by s1 consisting entirely of the characters found in s2.
Or, in the case of wcscspn(), the characters not found in s2.
Return Value
The length of the string pointed to by s1 consisting solely of the characters in s2 (in the case of wcsspn())
or of the characters not in s2 (in th ecase of wcscspn()).
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t str1[] = L"a banana";
6 wchar_t str2[] = L"the bolivian navy on maneuvers in the south pacific";
7 int n;
8
9 // how many letters in str1 until we reach something that's not a vowel?
10 n = wcsspn(str1, L"aeiou");
11 wprintf(L"%d\n", n); // n == 1, just "a"
12
See Also
wcschr(), wcsrchr(), strspn()
69.22 wcspbrk()
Search a wide string for one of a set of wide characters
Synopsis
#include <wchar.h>
Description
This is the wide character variant of strpbrk().
It finds the first occurrance of any of a set of wide characters in a wide string.
Return Value
Returns a pointer to the first character in the string s1 that exists in the string s2.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 // p points here after wcspbrk
6 // v
7 wchar_t *s1 = L"Hello, world!";
8 wchar_t *s2 = L"dow!"; // Match any of these chars
9
See Also
wcschr(), wmemchr(), strpbrk()
69.23 wcsstr()
Find a wide string in another wide string
Synopsis
#include <wchar.h>
Description
This is the wide variant of strstr().
Return Value
Returns a pointer to the location in s1 that contains s2.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t *str = L"The quick brown fox jumped over the lazy dogs.";
6 wchar_t *p;
7
8 p = wcsstr(str, L"lazy");
9 wprintf(L"%ls\n", p == NULL? L"null": p); // "lazy dogs."
10
See Also
wcschr(), wcsrchr(), wcsspn(), wcscspn(), strstr()
69.24 wcstok()
Tokenize a wide string
Synopsis
#include <wchar.h>
wchar_t *wcstok(wchar_t * restrict s1, const wchar_t * restrict s2,
wchar_t ** restrict ptr);
Description
This is the wide version of strtok().
And, like that one, it modifies the string s1. So make a copy of it first if you want to preserve the original.
One key difference is that wcstok() can be threadsafe because you pass in the pointer ptr to the current
state of the transformation. This gets initializers for you when s1 is initially passed in as non-NULL.
(Subsequent calls with a NULL s1 cause the state to update.)
Return Value
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 // break up the string into a series of space or
6 // punctuation-separated words
7 wchar_t str[] = L"Where is my bacon, dude?";
8 wchar_t *token;
9 wchar_t *state;
10
Output:
Word: "Where"
Word: "is"
Word: "my"
Word: "bacon"
Word: "dude"
See Also
strtok()
69.25 wcslen()
Returns the length of a wide string
Synopsis
#include <wchar.h>
Description
This is the wide counterpart to strlen().
Return Value
Returns the number of wide characters before the wide NUL terminator.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wchar_t *s = L"Hello, world!"; // 13 characters
6
See Also
strlen()
69.26 wcsftime()
Formatted date and time output
Synopsis
#include <time.h>
#include <wchar.h>
Description
This is the wide equivalent to strftime(). See that reference page for details.
maxsize here refers to the maximum number of wide characters that can be in the result string.
Return Value
If successful, returns the number of wide characters written.
If not successful because the result couldn’t fit in the space alloted, 0 is returned and the contents of the
string could be anything.
Example
1 #include <wchar.h>
2 #include <time.h>
3
6 int main(void)
7 {
8 wchar_t s[BUFSIZE];
9 time_t now = time(NULL);
10
See Also
strftime()
Synopsis
#include <wchar.h>
Description
These functions convert between single byte characters and wide characters, and vice-versa.
Even though ints are involved, don’t let this mislead you; they’re effectively converted to unsigned
chars internally.
The characters in the basic character set are guaranteed to be a single byte.
Return Value
btowc() returns the single-byte character as a wide character. Returns WEOF if EOF is passed in, or if the
byte doesn’t correspond to a valid wide character.
wctob() returns the wide character as a single-byte character. Returns EOF if WEOF is passed in, or if the
wide character doesn’t correspond to a value single-byte character.
See mbtowc() and wctomb() for multibyte to wide character conversion.
Example
1 #include <wchar.h>
2
3 int main(void)
4 {
5 wint_t wc = btowc('B'); // Convert single byte to wide char
674 Chapter 69. <wchar.h> Wide Character Handling
Output:
Wide character: B
Single-byte character: B
See Also
mbtowc(), wctomb()
69.28 mbsinit()
Test if an mbstate_t is in the initial conversion state
Synopsis
#include <wchar.h>
Description
For a given conversion state in a mbstate_t variable, this function determines if it’s in the initial conver-
sion state.
Return Value
Returns non-zero if the value pointed to by ps is in the initial conversion state, or if ps is NULL.
Returns 0 if the value pointed to by ps is not in the initial conversion state.
Example
For me, this example doesn’t do anything exciting, saying that the mbstate_t variable is always in the
initial state. Yay.
But if have a stateful encoding like 2022-JP, try messing around with this to see if you can get into an
intermediate state.
This program has a bit of code at the top that reports if your locale’s encoding requires any state.
1 #include <locale.h> // For setlocale()
2 #include <string.h> // For memset()
3 #include <stdlib.h> // For mbtowc()
4 #include <wchar.h>
5
6 int main(void)
7 {
8 mbstate_t state;
9 wchar_t wc[128];
10
69.29. mbrlen() 675
11 setlocale(LC_ALL, "");
12
See Also
mbtowc(), wctomb(), mbrtowc(), wcrtomb()
69.29 mbrlen()
Compute the number of bytes in a multibyte character, restartably
Synopsis
#include <wchar.h>
Description
This is the restartable version of mblen().
It inspects at most n bytes of the string s to see how many bytes in this character.
The conversion state is stored in ps.
This function doesn’t have the functionality of mblen() that allowed you to query if this character encod-
ing was stateful and to reset the internal state.
Return Value
Returns the number of bytes required for this multibyte character.
Returns (size_t)(-1) if the data in s is not a valid multibyte character.
Returns (size_t)(-2) if the data is s is a valid but not complete multibyte character.
Example
If your character set doesn’t support the Euro symbol “€”, substitute the Unicode escape sequence \u20ac,
below.
1 #include <locale.h> // For setlocale()
2 #include <string.h> // For memset()
3 #include <wchar.h>
4
5 int main(void)
676 Chapter 69. <wchar.h> Wide Character Handling
6 {
7 mbstate_t state;
8 int len;
9
10 setlocale(LC_ALL, "");
11
Output:
Length of 'B' is 1 byte(s)
Length of '€' is 3 byte(s)
See Also
mblen()
69.30 mbrtowc()
Convert multibyte to wide characters restartably
Synopsis
#include <wchar.h>
Description
This is the restartable counterpart to mbtowc().
It converts individual characters from multibyte to wide, tracking the conversion state in the variable
pointed to by ps.
At most n bytes are inspected for conversion to a wide character.
These two variants are identical and cause the state pointed to by ps to be set to the initial conversion
state:
mbrtowc(NULL, NULL, 0, &state);
mbrtowc(NULL, "", 1, &state);
Also, if you’re just interested in the length in bytes of the multibyte character, you can pass NULL for pwc
and nothing will be stored for the wide character:
int len = mbrtowc(NULL, "€", 5, &state);
This function doesn’t have the functionality of mbtowc() that allowed you to query if this character en-
coding was stateful and to reset the internal state.
69.31. wcrtomb() 677
Return Value
On success, returns a positive number corresponding to the number of bytes in the multibyte character.
Returns (size_t)(-2) if the data is s is a valid but not complete multibyte character.
Example
If your character set doesn’t support the Euro symbol “€”, substitute the Unicode escape sequence \u20ac,
below.
1 #include <string.h> // For memset()
2 #include <stdlib.h> // For mbtowc()
3 #include <locale.h> // For setlocale()
4 #include <wchar.h>
5
6 int main(void)
7 {
8 mbstate_t state;
9
12 setlocale(LC_ALL, "");
13
16 wchar_t wc;
17 int bytes;
18
Output on my system:
State dependency: 0
L'€' takes 3 bytes as multibyte char '€'
See Also
mbtowc(), wcrtomb()
69.31 wcrtomb()
Convert wide to multibyte characters restartably
Synopsis
#include <wchar.h>
Description
This is the restartable counterpart to wctomb().
It converts individual characters from wide to multibyte, tracking the conversion state in the variable
pointed to by ps.
The destination array s should be at least MB_CUR_MAX2 bytes in size—you won’t get anything bigger back
from this function.
Note that the values in this result array won’t be NUL-terminated.
If you pass a wide NUL character in, the result will contain any bytes needed to restore the conversion
state to its initial state followed by a NUL character, and the state pointed to by ps will be reset to its
initial state:
// Reset state
wcrtomb(mb, L'\0', &state)
If you don’t care about the results (i.e. you’re just interested in resetting the state or getting the return
value), you can do this by passing NULL for s:
wcrtomb(NULL, L'\0', &state); // Reset state
This function doesn’t have the functionality of wctomb() that allowed you to query if this character en-
coding was stateful and to reset the internal state.
Return Value
On success, returns the number of bytes needed to encode this wide character in the current locale.
If the input is an invalid wide character, errno will be set to EILSEQ and the function returns (size_t)(-
1). If this happens, all bets are off for the conversion state, so you might as well reset it.
Example
If your character set doesn’t support the Euro symbol “€”, substitute the Unicode escape sequence \u20ac,
below.
1 #include <string.h> // For memset()
2 #include <stdlib.h> // For mbtowc()
3 #include <locale.h> // For setlocale()
4 #include <wchar.h>
5
6 int main(void)
7 {
8 mbstate_t state;
9
12 setlocale(LC_ALL, "");
13
2
This is a variable, not a macro, so if you use it to define an array, it’ll be a variable-length array.
69.32. mbsrtowcs() 679
See Also
mbrtowc(), wctomb(), errno
69.32 mbsrtowcs()
Convert a multibyte string to a wide character string restartably
Synopsis
#include <wchar.h>
Description
This is the restartable version of mbstowcs().
It converts a multibyte string to a wide character string.
The result is put in the buffer pointed to by dst, and the pointer src is updated to indicate how much of
the string was consumed (unless dst is NULL).
At most len wide characters will be stored.
This also takes a pointer to its own mbstate_t variable in ps for holding the conversion state.
You can set dst to NULL if you only care about the return value. This could be useful for getting the
number of characters in a multibyte string.
In the normal case, the src string will be consumed up to the NUL character, and the results will be stored
in the dst buffer, including the wide NUL character. In this case, the pointer pointed to by src will be
set to NULL. And the conversion state will be set to the initial conversion state.
If things go wrong because the source string isn’t a valid sequence of characters, conversion will stop and
the pointer pointed to by src will be set to the address just after the last successfully-translated multibyte
character.
Return Value
If successful, returns the number of characters converted, not including any NUL terminator.
If the multibyte sequence is invalid, the function returns (size_t)(-1) and errno is set to EILSEQ.
Example
Here we’ll convert the string “€5 ± π” into a wide character string:
1 #include <locale.h> // For setlocale()
2 #include <string.h> // For memset()
3 #include <wchar.h>
4
5 #define WIDE_STR_SIZE 10
6
7 int main(void)
8 {
9 const char *mbs = "€5 ± π"; // That's the exact price range
10
11 wchar_t wcs[WIDE_STR_SIZE];
680 Chapter 69. <wchar.h> Wide Character Handling
12
13 setlocale(LC_ALL, "");
14
15 mbstate_t state;
16 memset(&state, 0, sizeof state);
17
Output:
Wide string L"€5 ± π" is 6 characters
Here’s another example of using mbsrtowcs() to get the length in characters of a multibyte string even if
the string is full of multibyte characters. This is in contrast to strlen(), which returns the total number
of bytes in the string.
1 #include <stdio.h> // For printf()
2 #include <locale.h> // For setlocale()
3
17 int main(void)
18 {
19 setlocale(LC_ALL, "");
20
Output on my system:
"€5 ± π" is 6 characters...
but it's 10 bytes!
See Also
mbrtowc(), mbstowcs(), wcsrtombs(), strlen(), errno
69.33 wcsrtombs()
Convert a wide character string to a multibyte string restartably
69.33. wcsrtombs() 681
Synopsis
#include <wchar.h>
Description
If you have a wide character string, you can convert it to a multibyte character string in the current locale
using this function.
At most len bytes of data will be stored in the buffer pointed to by dst. Conversion will stop just after
the NUL terminator is copied, or len bytes get copied, or some other error occurs.
If dst is a NULL pointer, no result is stored. You might do this if you’re just interested in the return value
(nominally the number of bytes this would use in a multibyte string, not including the NUL terminator).
If dst is not a NULL pointer, the pointer pointed to by src will get modified to indicate how much of the
data was copied. If it contains NULL at the end, it means everything went well. In this case, the state ps
will be set to the initial conversion state.
If len was reached or an error occurred, it’ll point one address past dst+len.
Return Value
If everything goes well, returns the number of bytes needed for the multibyte string, not counting the NUL
terminator.
If any character in the string doesn’t correspond to a valid multibyte character in the currently locale, it
returns (size_t)(-1) and EILSEQ is stored in errno.
Example
Here we’ll convert the wide string “€5 ± π” into a multibyte character string:
1 #include <locale.h> // For setlocale()
2 #include <string.h> // For memset()
3 #include <wchar.h>
4
5 #define MB_STR_SIZE 20
6
7 int main(void)
8 {
9 const wchar_t *wcs = L"€5 ± π"; // That's the exact price range
10
11 char mbs[MB_STR_SIZE];
12
13 setlocale(LC_ALL, "");
14
15 mbstate_t state;
16 memset(&state, 0, sizeof state);
17
Here’s another example helper function that malloc()s just enough memory to hold the converted string,
then returns the result. (Which must later be freed, of course, to prevent leaking memory.)
682 Chapter 69. <wchar.h> Wide Character Handling
11 mbstate_t state;
12 memset(&state, 0, sizeof state);
13
39 // Success!
40 return mbs;
41 }
42
43 int main(void)
44 {
45 char *mbs = get_mb_string(L"€5 ± π");
46
49 free(mbs);
50 }
See Also
wcrtomb(), wcstombs(), mbsrtowcs(), errno
Chapter 70
Function Description
iswalnum() Test if a wide character is alphanumeric.
iswalpha() Tests if a wide character is alphabetic
iswblank() Tests if this is a wide blank character
iswcntrl() Tests if this is a wide control character.
iswctype() Determine wide character classification
iswdigit() Test if this wide character is a digit
iswgraph() Test to see if a wide character is a printable non-space
iswlower() Tests if a wide character is lowercase
iswprint() Tests if a wide character is printable
iswpunct() Test if a wide character is punctuation
iswspace() Test if a wide character is whitespace
iswupper() Tests if a wide character is uppercase
iswxdigit() Tests if a wide character is a hexadecimal digit
towctrans() Convert wide characters to upper or lowercase
towlower() Convert an uppercase wide character to lowercase
towupper() Convert a lowercase wide character to uppercase
wctrans() Helper function for towctrans()
wctype() Helper function for iswctype()
70.1 iswalnum()
Test if a wide character is alphanumeric.
Synopsis
#include <wctype.h>
683
684 Chapter 70. <wctype.h> Wide Character Classification and Transformation
Description
Basically tests if a character is alphabetic (A-Z or a-z) or a digit (0-9). But some other characters might
also qualify based on the locale.
This is equivalent to testing if iswalpha() or iswdigit() is true.
Return Value
Returns true if the character is alphanumeric.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswalnum(L'a')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswalnum(L'B')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswalnum(L'5')? L"yes": L"no"); // yes
11 wprintf(L"%ls\n", iswalnum(L'?')? L"yes": L"no"); // no
12 }
See Also
iswalpha(), iswdigit(), isalnum()
70.2 iswalpha()
Tests if a wide character is alphabetic
Synopsis
#include <wctype.h>
Description
Basically tests if a character is alphabetic (A-Z or a-z). But some other characters might also qualify based
on the locale. (If other characters qualify, they won’t be control characters, digits, punctuation, or spaces.)
This is the same as testing for iswupper() or iswlower().
Return Value
Returns true if the character is alphabetic.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
70.3. iswblank() 685
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswalpha(L'a')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswalpha(L'B')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswalpha(L'5')? L"yes": L"no"); // no
11 wprintf(L"%ls\n", iswalpha(L'?')? L"yes": L"no"); // no
12 }
See Also
iswalnum(), isalpha()
70.3 iswblank()
Tests if this is a wide blank character
Synopsis
#include <wctype.h>
Description
Blank characters are whitespace that are also used as word separators on the same line. In the “C” locale,
the only blank characters are space and tab.
Other locales might define other blank characters.
Return Value
Returns true if this is a blank character.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswblank(L' ')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswblank(L'\t')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswblank(L'\n')? L"yes": L"no"); // no
11 wprintf(L"%ls\n", iswblank(L'a')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswblank(L'?')? L"yes": L"no"); // no
13 }
See Also
iswspace(), isblank()
686 Chapter 70. <wctype.h> Wide Character Classification and Transformation
70.4 iswcntrl()
Tests if this is a wide control character.
Synopsis
#include <wctype.h>
Description
The spec is pretty barren, here. But I’m just going to assume that it works like the non-wide version. So
let’s look at that.
A control character is a locale-specific non-printing character.
For the “C” locale, this means control characters are in the range 0x00 to 0x1F (the character right before
SPACE) and 0x7F (the DEL character).
Basically if it’s not an ASCII (or Unicode less than 128) printable character, it’s a control character in the
“C” locale.
Probably.
Return Value
Returns true if this is a control character.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswcntrl(L'\t')? L"yes": L"no"); // yes (tab)
9 wprintf(L"%ls\n", iswcntrl(L'\n')? L"yes": L"no"); // yes (newline)
10 wprintf(L"%ls\n", iswcntrl(L'\r')? L"yes": L"no"); // yes (return)
11 wprintf(L"%ls\n", iswcntrl(L'\a')? L"yes": L"no"); // yes (bell)
12 wprintf(L"%ls\n", iswcntrl(L' ')? L"yes": L"no"); // no
13 wprintf(L"%ls\n", iswcntrl(L'a')? L"yes": L"no"); // no
14 wprintf(L"%ls\n", iswcntrl(L'?')? L"yes": L"no"); // no
15 }
See Also
iscntrl()
70.5 iswdigit()
Test if this wide character is a digit
70.6. iswgraph() 687
Synopsis
#include <wctype.h>
Description
Tests if the wide character is a digit (0-9).
Return Value
Returns true if the character is a digit.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswdigit(L'0')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswdigit(L'5')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswdigit(L'a')? L"yes": L"no"); // no
11 wprintf(L"%ls\n", iswdigit(L'B')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswdigit(L'?')? L"yes": L"no"); // no
13 }
See Also
iswalnum(), isdigit()
70.6 iswgraph()
Test to see if a wide character is a printable non-space
Synopsis
#include <wctype.h>
Description
Returns true if this is a printable (non-control) character and also not a whitespace character.
Basically if iswprint() is true and iswspace() is false.
Return Value
Returns true if this is a printable non-space character.
688 Chapter 70. <wctype.h> Wide Character Classification and Transformation
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswgraph(L'0')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswgraph(L'a')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswgraph(L'B')? L"yes": L"no"); // yes
11 wprintf(L"%ls\n", iswgraph(L'?')? L"yes": L"no"); // yes
12 wprintf(L"%ls\n", iswgraph(L' ')? L"yes": L"no"); // no
13 wprintf(L"%ls\n", iswgraph(L'\n')? L"yes": L"no"); // no
14 }
See Also
iswprint(), iswspace(), isgraph()
70.7 iswlower()
Tests if a wide character is lowercase
Synopsis
#include <wctype.h>
Description
Tests if a character is lowercase, in the range a-z.
In other locales, there could be other lowercase characters. In all cases, to be lowercase, the following
must be true:
!iswcntrl(c) && !iswdigit(c) && !iswpunct(c) && !iswspace(c)
Return Value
Returns true if the wide character is lowercase.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswlower(L'c')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswlower(L'0')? L"yes": L"no"); // no
70.8. iswprint() 689
See Also
islower(), iswupper(), iswalpha(), towupper(), towlower()
70.8 iswprint()
Tests if a wide character is printable
Synopsis
#include <wctype.h>
Description
Tests if a wide character is printable, including space (' '). So like isgraph(), except space isn’t left
out in the cold.
Return Value
Returns true if the wide character is printable, including space (' ').
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswprint(L'c')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswprint(L'0')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswprint(L' ')? L"yes": L"no"); // yes
11 wprintf(L"%ls\n", iswprint(L'\r')? L"yes": L"no"); // no
12 }
See Also
isprint(), iswgraph(), iswcntrl()
70.9 iswpunct()
Test if a wide character is punctuation
690 Chapter 70. <wctype.h> Wide Character Classification and Transformation
Synopsis
#include <wctype.h>
Description
Tests if a wide character is punctuation.
This means for any given locale:
!isspace(c) && !isalnum(c)
Return Value
True if the wide character is punctuation.
Example
Results may vary based on locale.
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswpunct(L',')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswpunct(L'!')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswpunct(L'c')? L"yes": L"no"); // no
11 wprintf(L"%ls\n", iswpunct(L'0')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswpunct(L' ')? L"yes": L"no"); // no
13 wprintf(L"%ls\n", iswpunct(L'\n')? L"yes": L"no"); // no
14 }
See Also
ispunct(), iswspace(), iswalnum()
70.10 iswspace()
Test if a wide character is whitespace
Synopsis
#include <wctype.h>
Description
Tests if c is a whitespace character. These are probably:
• Space (' ')
• Formfeed ('\f')
70.11. iswupper() 691
• Newline ('\n')
• Carriage Return ('\r')
• Horizontal Tab ('\t')
• Vertical Tab ('\v')
Other locales might specify other whitespace characters. iswalnum(), iswgraph(), and iswpunct()
are all false for all whitespace characters.
Return Value
True if the character is whitespace.
Example
Results may vary based on locale.
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswspace(L' ')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswspace(L'\n')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswspace(L'\t')? L"yes": L"no"); // yes
11 wprintf(L"%ls\n", iswspace(L',')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswspace(L'!')? L"yes": L"no"); // no
13 wprintf(L"%ls\n", iswspace(L'c')? L"yes": L"no"); // no
14 }
See Also
isspace(), iswblank()
70.11 iswupper()
Tests if a wide character is uppercase
Synopsis
#include <wctype.h>
Description
Tests if a character is uppercase in the current locale.
To be uppercase, the following must be true:
!iscntrl(c) && !isdigit(c) && !ispunct(c) && !isspace(c)
Return Value
Returns true if the wide character is uppercase.
692 Chapter 70. <wctype.h> Wide Character Classification and Transformation
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswupper(L'B')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswupper(L'c')? L"yes": L"no"); // no
10 wprintf(L"%ls\n", iswupper(L'0')? L"yes": L"no"); // no
11 wprintf(L"%ls\n", iswupper(L'?')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswupper(L' ')? L"yes": L"no"); // no
13 }
See Also
isupper(), iswlower(), iswalpha(), towupper(), towlower()
70.12 iswxdigit()
Tests if a wide character is a hexadecimal digit
Synopsis
#include <wctype.h>
Description
Returns true if the wide character is a hexadecimal digit. Namely if it’s 0-9, a-f, or A-F.
Return Value
True if the character is a hexadecimal digit.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // testing this char
7 // v
8 wprintf(L"%ls\n", iswxdigit(L'B')? L"yes": L"no"); // yes
9 wprintf(L"%ls\n", iswxdigit(L'c')? L"yes": L"no"); // yes
10 wprintf(L"%ls\n", iswxdigit(L'2')? L"yes": L"no"); // yes
11 wprintf(L"%ls\n", iswxdigit(L'G')? L"yes": L"no"); // no
12 wprintf(L"%ls\n", iswxdigit(L'?')? L"yes": L"no"); // no
13 }
70.13. iswctype() 693
See Also
isxdigit(), iswdigit()
70.13 iswctype()
Determine wide character classification
Synopsis
#include <wctype.h>
Description
This is the Swiss Army knife of classification functions; it’s all the other ones rolled into one.
You call it with something like this:
if (iswctype(c, wctype("digit"))) // or "alpha" or "space" or...
The difference is that you can specify the type of matching you want to do as a string at runtime, which
might be convenient.
iswctype() relies on the return value from the wctype() call to get its work done.
Stolen from the spec, here are the iswctype() calls and their equivalents:
See the wctype() documentation for how that helper function works.
Return Value
Returns true if the wide character wc matches the character class in desc.
Example
Test for a given character classification at when the classification isn’t known at compile time:
694 Chapter 70. <wctype.h> Wide Character Classification and Transformation
5 int main(void)
6 {
7 wchar_t c; // Holds a single wide character (to test)
8 char desc[128]; // Holds the character class
9
18 if (t == 0)
19 // If the type is 0, it's an unknown class
20 wprintf(L"Unknown character class: \"%s\"\n", desc);
21 else {
22 // Otherwise, let's test the character and see if its that
23 // classification
24 if (iswctype(c, t))
25 wprintf(L"Yes! '%lc' is %s!\n", c, desc);
26 else
27 wprintf(L"Nope! '%lc' is not %s.\n", c, desc);
28 }
29 }
Output:
Enter a character and character class: 5 digit
Yes! '5' is digit!
See Also
wctype()
70.14 wctype()
Helper function for iswctype()
Synopsis
#include <wctype.h>
Description
This function returns an opaque value for the given property that is meant to be passed as the second
argument to iswctype().
The returned value is of type wctype_t.
Valid properties in all locales are:
"alnum" "alpha" "blank" "cntrl"
"digit" "graph" "lower" "print"
"punct" "space" "upper" "xdigit"
Other properties might be defined as determined by the LC_CTYPE category of the current locale.
See the iswctype() reference page for more usage details.
Return Value
Returns the wctype_t value associated with the given property.
If an invalid value is passed for property, returns 0.
Example
Test for a given character classification at when the classification isn’t known at compile time:
1 #include <stdio.h> // for fflush(stdout)
2 #include <wchar.h>
3 #include <wctype.h>
4
5 int main(void)
6 {
7 wchar_t c; // Holds a single wide character (to test)
8 char desc[128]; // Holds the character class
9
18 if (t == 0)
19 // If the type is 0, it's an unknown class
20 wprintf(L"Unknown character class: \"%s\"\n", desc);
21 else {
22 // Otherwise, let's test the character and see if its that
23 // classification
24 if (iswctype(c, t))
25 wprintf(L"Yes! '%lc' is %s!\n", c, desc);
26 else
27 wprintf(L"Nope! '%lc' is not %s.\n", c, desc);
28 }
29 }
Output:
Enter a character and character class: 5 digit
Yes! '5' is digit!
See Also
iswctype()
70.15 towlower()
Convert an uppercase wide character to lowercase
Synopsis
#include <wctype.h>
Description
If the character is upper (i.e. iswupper(c) is true), this function returns the corresponding lowercase
letter.
Return Value
If the letter wc is uppercase, a lowercase version of that letter will be returned according to the current
locale.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // changing this char
7 // v
8 wprintf(L"%lc\n", towlower(L'B')); // b (made lowercase!)
9 wprintf(L"%lc\n", towlower(L'e')); // e (unchanged)
10 wprintf(L"%lc\n", towlower(L'!')); // ! (unchanged)
11 }
See Also
tolower(), towupper(), iswlower(), iswupper()
70.16. towupper() 697
70.16 towupper()
Convert a lowercase wide character to uppercase
Synopsis
#include <wctype.h>
Description
If the character is lower (i.e. iswlower(c) is true), this function returns the corresponding uppercase
letter.
Return Value
If the letter wc is lowercase, an uppercase version of that letter will be returned according to the current
locale.
Example
1 #include <wchar.h>
2 #include <wctype.h>
3
4 int main(void)
5 {
6 // changing this char
7 // v
8 wprintf(L"%lc\n", towupper(L'B')); // B (unchanged)
9 wprintf(L"%lc\n", towupper(L'e')); // E (made uppercase!)
10 wprintf(L"%lc\n", towupper(L'!')); // ! (unchanged)
11 }
See Also
toupper(), towlower(), iswlower(), iswupper()
70.17 towctrans()
Convert wide characters to upper or lowercase
Synopsis
#include <wctype.h>
Description
This is the Swiss Army knife of character conversion functions; it’s all the other ones rolled into one. And
by “all the other ones” I mean towupper() and towlower(), since those are the only ones there are.
You call it with something like this:
if (towctrans(c, wctrans("toupper"))) // or "tolower"
The difference is that you can specify the type of conversion you want to do as a string at runtime, which
might be convenient.
towctrans() relies on the return value from the wctrans() call to get its work done.
See the wctrans() documentation for how that helper function works.
Return Value
Returns the character wc as if run through towupper() or towlower(), depending on the value of desc.
If the character already matches the classification, it is returned as-is.
Example
1 #include <stdio.h> // for fflush(stdout)
2 #include <wchar.h>
3 #include <wctype.h>
4
5 int main(void)
6 {
7 wchar_t c; // Holds a single wide character (to test)
8 char desc[128]; // Holds the conversion type
9
18 if (t == 0)
19 // If the type is 0, it's an unknown conversion type
20 wprintf(L"Unknown conversion: \"%s\"\n", desc);
21 else {
22 // Otherwise, let's do the conversion
23 wint_t result = towctrans(c, t);
24 wprintf(L"'%lc' -> %s -> '%lc'\n", c, desc, result);
25 }
26 }
Output on my system:
70.18. wctrans() 699
See Also
wctrans(), towupper(), towlower()
70.18 wctrans()
Helper function for towctrans()
Synopsis
#include <wctype.h>
Description
This is a helper function for generating the second argument to towctrans().
You can pass in one of two things for the property:
• toupper to make towctrans() behave like towupper()
• tolower to make towctrans() behave like towlower()
Return Value
On success, returns a value that can be used as the desc argument to towctrans().
Otherwise, if the property isn’t recognized, returns 0.
Example
1 #include <stdio.h> // for fflush(stdout)
2 #include <wchar.h>
3 #include <wctype.h>
4
5 int main(void)
6 {
7 wchar_t c; // Holds a single wide character (to test)
8 char desc[128]; // Holds the conversion type
9
14
18 if (t == 0)
19 // If the type is 0, it's an unknown conversion type
20 wprintf(L"Unknown conversion: \"%s\"\n", desc);
21 else {
22 // Otherwise, let's do the conversion
23 wint_t result = towctrans(c, t);
24 wprintf(L"'%lc' -> %s -> '%lc'\n", c, desc, result);
25 }
26 }
Output on my system:
Enter a character and conversion type: b toupper
'b' -> toupper -> 'B'
See Also
towctrans()
Index
701
702 INDEX