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
char
type 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
false
and 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
,p2
is 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
extern
modifier. Functions areextern
by default. - The
static
modifier is used to limit the visibility of a function to the file in which it is defined. Variables arestatic
by 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_t
is an unsigned integer type returned by thesizeof()
operator.%zu
is the format specifier for it.- The header
<stddef.h>
defines a typeptrdiff_t
that 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)
. typedef
does 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.
FILE
is a wrapper around a file descriptor with internal buffering.- VLA: generally not recommended, optional since C11.
wchar_t
is a wide (multibyte)char
used to represent unicode characters (likerune
in Go).- Use
static
for variables and functions that should not be visible from other files. - Use
const
for pointer function parameters if the function does not modify them. - Various
const
tips: 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-std
flag.
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-format
andclang-tidy
) - Code sanitizers: AddressSanitizer, MemorySanitizer, etc