C
The C programming language. The father of most modern programming languages.
Learn
- The C Programming Language (K&R)
- https://beej.us/guide/bgc
- #todo Modern C by Jens Gustedt
- #todo Deep C Secrets by Peter van der Linden
Notes
#todo Sort out.
- The most common way to build a C program is to compile each source file into an object file and then link them together.
- The
chartype is always 1 byte. - Modern C programs use standard types from
<stdint.h>instead ofint,long, etc. - Arrays are pointers to the first element. There is no way to calculate the length of an array passed to a function.
- All strings are
\0-terminated. This is howstrlen()calculates the length. - Historically, C didn’t have a boolean type: zero meant
falseand non-zero meanttrue. Now,<stdbool.h>exists. - There is a short form to define an array and initialize it with zeroes:
int arr[100] = {0};. sizeof()returns the size of a type in bytes. It is a compile-time operation.- Array/pointer equivalence rule:
a[b] == *(a+b). - Out-of-bounds array access results in undefined behavior.
- Pointer arithmetics:
ptr++moves to the next object of the same type. void*is a generic pointer that is used for arguments of any type (likeinterface{}in Go).- There are two operators to access struct fields:
.for structs and->for struct pointers. - Local variables are allocated on the stack, manually allocated memory - on the heap.
int* p1, p2;caveat: unlikep1,p2is not a pointer.- There is no zero value concept, uninitialized variables contain garbage.
- There can be multiple declarations, but only one definition.
- A global variable from one file cannot just be used in another file, because there is no global scope, only a file scope. First, it has to be (re)declared with the
externmodifier. Functions areexternby default. - The
staticmodifier is used to limit the visibility of a function to the file in which it is defined. Variables arestaticby default. - The name of an array is a synonym for the location of its first element:
int a[]; a == &a[0]. - C guarantees that zero (
NULL) is never a valid address, so a return value of zero can safely be used as a signal. - Pointer arithmetics: If two pointers point to members of the same array, then can be compared with
==,!=,>,<, etc. size_tis an unsigned integer type returned by thesizeof()operator.%zuis the format specifier for it.- The header
<stddef.h>defines a typeptrdiff_tthat is large enough to hold the signed difference of two pointer values. - Function pointers can be used to achieve polymorphism.
char s[] = "...": an array of chars (modifiable);char* s = "...": a pointer to a static string (non-modifiable).- Conventional names for command lines arguments:
int argc, char* argv[]. - Any pointer can be cast to
void*and back again without loss of information. - The size of a structure is NOT the sum of the sizes of its members because of memory alignment.
- A struct can have a flexible array member (must be last).
- Returning a pointer to a local variable from a function results in a dangling pointer.
- The standard idiom to traverse a linked list:
for (ptr = head; ptr != NULL; ptr = ptr->next). typedefdoes not create a new type, it just adds an alias to the existing type.- Union is a variable that may hold objects of different types and sizes. The largest type defines the size of the union.
- Assertions:
assert(): macro, runtime;static_assert(): since C23, keyword, compile time. - For a library, the header file is the API: expose as few things as possible and hide implementation details using opaque data types.
FILEis a wrapper around a file descriptor with internal buffering.- VLA: generally not recommended, optional since C11.
wchar_tis a wide (multibyte)charused to represent unicode characters (likerunein Go).- Use
staticfor variables and functions that should not be visible from other files. - Use
constfor pointer function parameters if the function does not modify them. - Various
consttips: https://matt.sh/sytycc int foo;vsextern int foo;in file scope: the former is a tentative definition that may act as a definition (implicitly initialized with 0) or as a declaration, the latter is always a declaration.
Best practices
- C99 minimum
- No code in headers
- Include guards in headers
- Minimal use of typedefs
- No macros
- No compiler extensions
Standards
| Name | Year | Description |
|---|---|---|
| K&R C | 1978 | The original version named after B.Kernighan and D.Ritchie |
| ANSI C | 1989 | The first language specification published by ANSI |
| C99 | 1999 | The most common version at the moment |
| C11 | 2011 | A major version introduced Unicode and multithreading support |
| C23 | 2023 | Not yet released |
💡 Hint
You can force the compiler to use a specific standard with the-stdflag.
Preprocessor
| Directive | Description |
|---|---|
#include |
includes the contents of a file during compilation |
#define |
replaces a token by an arbitrary sequence of characters |
#if, #elif, #else, #endif |
tests whether a condition is true |
#ifdef, #ifndef |
tests whether a name is (not) defined |
#error |
stops compilation with an error |
#embed |
(C23) includes the contents of a binary file |
#pragma once |
(non-standard) tells the compiler to include a file only once |
Modifiers
Type qualifiers:
| Keyword | Description |
|---|---|
const |
marks a variable as readonly; for a pointer marks the value it points to |
restrict |
tells the compiler that this memory block will only be accessed by a single pointer |
register |
tells the compiler that this value should be put into a register (so its address cannot be taken with &) |
volatile |
tells the compiler that this value might change outside the program |
Storage-class specifiers:
| Keyword | Lifetime | Visibility |
|---|---|---|
auto |
block scope | block scope |
static |
entire program | block scope (inside block) / file scope (outside block) |
extern |
entire program | entire program |
Defaults: auto for block scope objects, extern for file scope objects.
Stdlib
https://en.wikipedia.org/wiki/C_standard_library
Implementations:
- glibc: https://www.gnu.org/software/libc
- musl: https://musl.libc.org
Included in the ANSI standard:
| Header file | Contents | Examples |
|---|---|---|
<stdio.h> |
input and output | printf(), fopen() |
<stdlib.h> |
utility functions | malloc(), free(), exit() |
<ctype.h> |
character type tests | isalpha(), isdigit(), isspace() |
<string.h> |
string functions | strlen(), strcmp(), strcpy() |
<math.h> |
mathematical functions | log(), pow(), sqrt() |
<assert.h> |
diagnostics | assert(), static_assert() |
<stdarg.h> |
variable argument lists | va_start(), va_arg(), va_end() |
<signal.h> |
interrupt signals | signal() |
<time.h> |
date and time functions | time(), clock() |
<limits.h> |
limits of number types | INT_MIN/INT_MAX |
Compilers
- GCC: https://gcc.gnu.org
- Clang: https://clang.llvm.org
Tooling
- Formatter: clang-format
- Linter: clang-tidy
- Language server: clangd (includes both
clang-formatandclang-tidy) - Code sanitizers: AddressSanitizer, MemorySanitizer, etc