C/C++
Table of Contents
- 1. C Syntax
- 2. C++ Syntax
- 3. C Libraries
- 4. C++ Libraries
- 5. Assembly
- 6. Compilation
- 7. Language Servers
- 8. Utilities
- 9. Debugging
- 10. References
- C++ is a superset of C with zero overhead abstraction, including OOP.
1. C Syntax
1.1. Definition
Functions and variables is defined in two steps: declaration and initialization.
They can be declared and defined separately or simultaneously.
int a; // declaration
a = 10; // initialization
int b = 10;
int f(int a);
int f(int); // argument name is optional, but recommended for description
int f(int a) {
return 2 * a;
}
1.2. Pointer
A variable stored in the memory that holds memory address.
#include <stdio.h>
int n = 5;
int *p = &n; // initalize ('*' = 'pointer to') an integer. e.g. p = 0x7999990D
printf("%p\n", (void *)p);
printf("%d", *p); // print the ('*' = 'dereference of') the pointer
Deference
The type of the pointer determines how to dereference the pointer.
Therefore, the pointer to unknown type, void *, must be typecasted before being used.
Pointer to a struct stores the first memory address
of the struct. The arrow operator p->m can be used
to access the member of the pointed struct.
It is equivalent to deferencing the struct and
useing the dot operator (*p).m
Pointer to an array of struct automatically increments by the multiple of the size of the struct, when incremented by 1.
Function Pointer Declaration of function pointer takes special form.
int (*f_ptr)(int);
f_ptr = &f; // or just f_ptr = f
An example from signal.h that defines a function
that takes integer (int) and function pointer (void (*)(int))
and returns a function pointer (void (*...)(int)).
void (*signal(int, void (*)(int)))(int);
For clarity the same code can be written as follows:
typedef void (*sig_t)(int); // defining type "sig_t"
sig_t signal(int, sig_t);
1.3. Array
Array is declared with its size in square bracket, and the value can be initialized with braces.
#include <stdio.h>
int int_arr[5] = {1, 2, 3, 4, 5}; // aggregate initialization
char str_arr[] = "hello";
char *str_ptr = "world"; // this is special case
printf("%d\n", int_arr[2]);
printf("%s\n", str_arr);
printf("%s\n", str_ptr);
1.4. Struct
Sequence of data bundled together.
1.5. Control Flow
if
switch
switch (expression) {
case x:
break;
default:
break;
}
The matching continues to the next case unless break; is encountered.
1.6. Const
Define an unmodifiable variable for compiler.
const int *pfixes the dereference*pint *const pfixes the pointerp
1.7. Macro
#define VAR VAL#define MACRO(<args>) (EXPRESSION)##can be used for literal concatenation
#include <...>searches the default locations.#include "..."searches current directory.
1.8. extern
- External Linkage
Function is always linked externally, the symbols are exposed and linked to the definition in the other file.
On the other hand variables are linked internally, that is, defined privately, by default.
Each file declares its own variable. extern T a keyword is used
in order to share the same variable.
1.9. lvalue and rvalue
lvalue (locator value, or left value of assignment) has a fixed memory address,
and & operator can be used.
rvalue (read value, or right value of assignment) is temporary or literal that does not have persistent memory address.
Unnamed non-trivial expression is an prvalue (pure rvalue).
e.g. 1+1.
1.10. Others
volatile
- Indicate that the thing is not persistent.
- Tells the compiler not to do anything smart such as eliminating duplicate codes. This is useful for memory-mapped hardwares.
typedef struct { ... } <type>
- Only the
<type>needs to be used for type specification in contrast tostruct <ident> { ... }for whichstruct nameneeds to be used.
2. C++ Syntax
C++ Standard is refered using the year it was published. e.g. C++23.
2.1. Reference
Pointer with compile-time reference counts.
- Reference to a reference is not allowed.
- References do not need to be dereferenced.
2.2. Range-For
Loop over the elements
std::vector<int> v;
for (auto &x: v) {
<body>
}
2.3. Structured Binding
Unpacking the values into multiple variables
std::unordered_map<std::string, std::string> m;
for (auto &[k, v]: m) {
<body>
}
Struct can be unpacked as well.
struct S {
int a;
std::string b;
};
S s();
auto [x, y] = s();
2.4. Lambda Function
auto lambda = [](int x) { return x * x; };
Unnamed function object called functor is defined.
[]capture surrounding variables.[=]capture all by value,[x]capturexby value[&]capture all by reference,[&x]capturexby reference.
The return type is inferred, but it can also be specified explicitly:
auto double = [](int n) -> int { return 2*n; };
The lambda function itself can be used with this const auto& since C++23:
auto fib = [](this const auto& self, int n){
if (n <= 1) return n;
return self(n-2) + self(n-1);
};
2.5. Class
struct is extended to have the exact same functionalities of class.
The difference is that the members of struct is public
and inherited publicly, by default.
2.5.1. Method
Any non-static member function can use this that points to the
object itself.
2.5.2. Constructor
class Foo {
Foo(<params>) : <member initialization> {
<body>
}
#optional
Foo(std::intializer_list<T>) {
<body>
}
}
- member initalization happens during object construction
- It is a comma seperated list of constructor calls: e.g.
a(5), b{param1, param2}. - References and const variables are required to be initialized here.
- It is a comma seperated list of constructor calls: e.g.
Foo a{1, 2, 3};
Here, {} invokes the list initialization which is the second constructor. Narrowing (of the type) is not allowed when {} is used.
2.5.3. Destructor
Invoked automatically when the object gets out of the scope. Useful for memory management.
class Foo {
~Foo() {
<body>
}
}
2.5.4. Inheritance
class Child : public Parent {
private:
...
protected:
...
public:
...
}
publickeeps thepublicstate of the properties and methods.protectedchangepublicintoprotectedprivatechangepublicandprotectedintoprivate
2.5.5. Abstract Class
Class can have virtual methods and destructor:
class ABS {
virtual int method1(int a) = 0; // purely virtual
virtual int method2(int b) {
...
} // default implementation
virtual ~ABS() = default; // you want this
};
class Derived : public ABS {
int method1(int a) override {
...
}
int method2(int b) override {
...
}
~Derived() override {
...
}
};
Virtual methods are registered to a special private property called virtual table (vtable) that exists for the base class and its derivatives. Purely virtual methods are marked as no implementation.
When the child class override
the methods, they are registered to the vtable that survives the upcasting into the base class.
When the method is being called from the base class, they look the address in the vtable and call
the method of the derived class.
The same applies for the destructor as well. You need to set the destructor of abstract class virtual, because you want to call the destructor of the concrete class. The concrete destructor would also call the parent destructor implicitly, so the virtual destructor will never get replaced, only get extended.
2.5.6. Operator Overloading
The standard operator can be redefined by defining
operator<op> method for the first argument of <op>.
The friend operator<op> can be used in the case the main
object is on the right of <op>.
2.6. Specifier
2.6.1. constexpr
Evaluated at compile time
constexpr int var = 20;
2.6.2. noexcept
The function is asserted to not throw error. It is okay if every error within the function is catched.
void safe_function() noexcept {
// no exception is allowed
}
If exception is raised within safe_function, the normal unwinding is bypassed,
and std::terminate is called immediately.
The specifier can be applied conditionally with noexcept(<condition>)
2.7. C++ Header
- No
.hextension
Modern header files stored in
/usr/include/c++/<version>//usr/include/x86_64-linux-gnu/c++/<version>//usr/include/
std namespaces are used by the standard libraries.
2.8. Template
template <typename T>
// function, class, `using`
Template is a blueprint that is instantiated on demand at compile-time.
Template is instantiated for specific types based on the content of the C file.
The proper compiler need to see the instances. Otherwise they will not be available for linking.
The template can be instantiated manually by declaring instances with template class Class<Type>;.
2.8.1. SFINAE
- Substitution Failure Is Not An Error
When template instantiation fails, the compiler looks for another matching template instead of throwing an error. If every template fails, then error is thworn.
2.8.2. Concept
#include <concepts>- Since C++20, via the definition of
__cpp_concepts
A template is instantiated if the concepts are met.
Concepts can be asserted in two ways. In the template
template<Incrementable T>
void f(T);
or in the requires clause
template<T> requires Incrementable<T>
void f(T);
2.9. Attribute
[[maybe_unused]]suppress unused warning for a variable
[[maybe_unused]] std::string a{"hello"};
3. C Libraries
3.1. stdio.h
printf%s%d%f
scanfFILE *fopenfprintf(FILE *file, const char *format, ...)fscanf
3.2. stdlib.h
void *malloc(size_t size)void free(void *ptr)char *getenv(const char *name)get environment variableint system(const char *string)execute the command given bystringint rand(void)generate random numbervoid srand(unsigned int seed)set seed
void exit(int status)
3.3. stdarg.h
- Variadic arguments. (Unknown number of arguments)
3.4. unistd.h
ssize_t read(int fd, void buf[.count], size_t count)execfamilyexecl(const char *path, const char *arg, ..., (char *)NULL);variable-length argument listexecv(const char *path, char *const argv[]);array of stringsexec*p(const char *file, ...);PATH-searching variantexec*e(..., char *const envp[]);set environment variables
brk()set the program breaksbrk()increment the program break and return the previous address
3.5. errno.h
- define the global variable
errno
3.6. signal.h
- The signals can come from the environment.
void (*signal(int sig, void (*func)(int)))(int)- Sets the signal handler.
- Predefined Signals: =SIGINT=(4), =SIGTERM=(6), …
- Signal Handlers: =SIGDFL=(1), =SIGERR=(2), =SIGIGN=(3)
int raise(int sig)
3.7. math.h
- mathematical functions
3.8. string.h
- string(
char *) manipulation
3.9. sys/types.h
size_t- Typically
unsigned intthat represent the size. It might vary depending on the system?
ssize_t- Typically
intthat represent the size, or the error value-1. - If
-1is returned, theerrnoglobal variable is expected to set to a number that representing the error message.
- Typically
mode_t- the type for the file permission node
- Constants are predefined:
S_IRWXU,S_IRUSR, … - It is the 5 digit octal number for the file permission. See ((669f0999-3389-4a74-92df-c0842ecd3c3c))
- Typically
sys/stat.h(includesys/types.h)mkdirmknodchmodumask
4. C++ Libraries
4.1. IO Libraries
4.1.1. iostream
std::coutthe output stream object<<operator outputs the right argument, and returnthis.
std::cin>>operator reads into the right argument, and returnthis.
4.1.2. print
- Since C++23, via the definition of
__cpp_lib_print std::print(std::format_string<Args...> fmt, Args&&... args)Python-like print function. std::printstd::println
4.2. Rich-pointer Libraries
4.2.1. memory
std::unique_ptr<T>wrapper of a pointer with automatically destructor according to the typeT.- The pointer returned by
mallocdoes not have destructor attached to it, and manualfreeis required.
- The pointer returned by
std::shared_ptr<T>wrapper of a pointer with reference count over multiple thread.
4.2.2. string
std::stringwrapper object of a heap-allocated stringstd::string_viewtype that can reference bothstd::stringand string literal.
4.2.3. array
std::array<T, length>stack-allocated fixed-size array
4.2.4. vector
std::vector<T>heap-allocated dynamic array.push_back(int n)
4.2.5. expected
- Since C++23
This library enables monadic error handling.
std::expected<T, E>object with error subtype defined bystd::unexpected(...)..and_then(<lambda>)run on success.or_else(<lambda>)run on failure.value()the success value.valule_or(<default>)return default in case of failure
4.2.6. utility
std::movethe ownership of the heap-allocated data is moved.- returning moved variable is unnecessary due to the Return Value Optimization (RVO) is already there.
4.2.7. ranges
4.2.7.1. Range Adaptors
- Since C++20
std::ranges::views::orstd::views::
Create a view object out of iterable with a pipe (|) symbol.
e.g.
std::vector<int> numbers = {1, 2, 3, 4};
auto view = numbers | std::views::filter([](int n) {return n % 2 == 0; });
filter(<lambda>)transform(<lambda>)all(),counted()take(<n>),drop(<n>)join(),reverse()iota(<start>, <end>)generate sequencerepeat(<value>)(C++23)
4.2.8. span
- Since C++20
std::span<T>object that refers to any contiguous sequence:std::string,std::vector,std::array, C array.
4.3. Others
4.3.1. algorithm
4.3.2. thread
std::this_threadcurrent thread objectstd::threadthread object initialized by giving it a function to execute- C++23
std::jthreadthread object with auto-joining after completion, and cancellation
5. Assembly
5.1. x8664
Register name with prefix
r: 64 bitse: 32 bits,
additionally
ax,bx,cx,dx: 16 bitsal,ah, …: 8 bits
Lables are defined with : at the end. A label can starts with ..
The label is equivalent to literal memory address.
5.1.1. GNU Syntax
- AT&T Syntax
Use prefixes for different kinds of symbols:
- Directives:
. - Register:
% - Immediate Value:
$,
Refer to memory like
disp(base,index,scale),
Binary operations act on the second argument.
Instruction with suffix
b(byte): 8 bitsw(word): 16 bitsl(long): 32 bitsq(quadword): 64 bits.
The data is read and wirrten as little endian, with the given address being the first address of the byte sequence.
5.1.2. Intel Syntax
- Directive
.intel_syntx
Do not have prefixes,
Refer to memory like
[expr]whereexprcan be arithmetic expression consists of register name and numbers,
Binary operations act on the first argument.
BYTE PTR, WORD PTR, DWORD PTR, QWORD PTR right after the instruction
indicates the width of the operation.
5.1.3. Instructions
| Instruction | Description |
|---|---|
mov A, B |
copy |
add A, B, sub A, B, mul A, B |
|
lea A, B |
load effective address: load the address of the memory reference |
call LABEL, ret |
subroutine |
5.2. syscall
It emits the instruction int 0x80 on Linux.
%raxsystem call number%rdi,%rsi,%rdx,%r10, … arguments for the call
%rax |
Name | Description |
|---|---|---|
| 0 | read | |
| 1 | write | |
| 2 | open | |
| 3 | close | |
| 60 | exit |
5.3. Assembler Directives
| Directive | Description |
|---|---|
.ascii "..." |
insert string data |
.asciz "..." |
insett string with zero attached |
.global SYMBOL |
expose SYMBOL to ld |
.text, .data, .bss |
set secion |
.equ VAR, VAL |
define a symbol |
.skip SIZE, FILL |
fill memory of SIZE with FILL |
5.4. Call Frame Information
- CFI
Keep track of the stack frames in the debugging section.
CFI is necessary when
- the compiler does optimization (
-fomit-frame-pointer) and not store former%rbp - exception handling
- need cross-platform consistency
5.5. Procedure Linkage Table
- PLT
The table contains the virtual addresses of the loaded shared objects, allowing different processes to use the shame physical memory for executables and shared objects.
For example, printf@plt initially points to the PLT setup code and
on the second time it is redirected to the loaded printf function directly.
6. Compilation
6.1. Compiler
6.1.1. gcc
GNU Compiler Collection (formerly, GNU C Compiler)
- Takes care of all the preprocessing (
cpp), (proper) compilation (cc1), assembly (as), and linking (ld).
General Options
-oSet the name of the target, by default an executable-cStop before linking-SStop before assembly-Eonly perform preprocessing, and output to the standard out-gdebugging-ggdbadd debugging information forgdb
Compiler Options
-I <dir>add the directory to the list of directory to be searched for header files./usr/include/,/usr/local/include/is searched by default.- The prefixes
=or$SYSROOTis replaced by sysroot prefix.
-e <entry>specify the entry point.-nostdlib,-nolibc-pieproduce a dynamically linked Position Indepnedent Executable.- It is the default behavior.
-no-pieto disable.
- It is the default behavior.
Linker Options
-l LIBRARYor-lLIBRARY-LDIRaddDIRto the list of library directory/usr/libby default
-sharedproduce a shared object
6.1.1.1. g++
gcc with the C++ library used by default when linking.
C++ Version
-std=c++NN
6.1.2. clang
LLVM based C/C++ Compiler
clang -S -emit-llvm FILEoutput the intermediate representation
6.2. Build System
6.2.1. make
- Parallel compilation tool
Options
-k,--keep-goingcompile as much as possible-j [N],--jobs [N]number of simultaneous jobs. unlimited ifNis not given.
6.2.1.1. Syntax
6.2.1.1.1. Variable
Variables are simply defined
VAR = value
and can be accessed anywhere with $(VAR).
Variable expansion happens after the special character exchange.
6.2.1.1.2. Rule
A rule is defined as follows
target ...: prerequisite ...
recipe
...
Prerequisites are other targets, and recipes are any commands.
Recipes must starts with TAB, unless .RECIPEPREFIX is set otherwise.
The first target that does not begin with . is the default goal.
make checks if a given goal matches any of the targets, then executes the matched recipe.
Target can contain % that matches any nonempty string.
% can be reused in the prerequisites to refer back to the matched string.
$@the target name$<the first prerequisite$?space-separated list of newly modified prerequisites$^all prerequisites
6.2.1.1.3. Recipe
@Stop the output of the command itself.
+
Force execution in the -n (no execution) mode.
6.2.1.2. Phony Targets
.PHONY: clean
clean:
rm *.o temp
Specify that the target file clean is not a file.
make does not check the existence of the phony target file.
6.2.2. cmake
Options
-S SRCDIR -B BUILDDIR -Dvar=valgenerate the build files--build BUILDDIR--install BUILDDIR--prefix CMAKE_INSTALL_PREFIXset the target directory for installation
6.2.2.1. Syntax
Specified in CMakeLists.txt
project(<name> [LANGUAGES <lang>])define projectfind_package(<package name> [REQUIRED])looks for<package name>Config.cmakeand use the packagefind_library()add_library()add tartget library. e.g..o,.a,.soadd_executable()add target executabletraget_link_libraries()
6.3. cpp
C Preprocessor
6.4. as
GNU Assembler
-ooutput file name-gdebug information
6.5. ld
GNU Linker (Loader)
-l<namespec>seach inlib<namespec>.aorlib<namespec>.so- It only searches for the symbols that the linker has seen so far. The library has to be specified after the source file.
- If
<namespec>looks like:filename,filenameis searched instead.
-( <filenames or -l options> -)search repeatedly until no undefined references left
7. Language Servers
7.1. clangd
7.1.1. Configuration
clangd can be configured in multiple ways.
.cland: configuration in YAML formatcompile_commands.json: automatically generated by CMake, or captured with the tools likebear.compile_flags.txt: plain text flags
Structure of .clangd looks like:
CompileFlags:
Add: [-std=c++20 ...]
8. Utilities
8.1. nm
Dump the symbol table and their attributes from a binary executable file.
8.2. objdump
-ddisassemble-remit relocation record
8.3. readelf
Read the metadata of ELF file.
-aall metadata
8.4. ldd
Print the shared objects required by program
8.5. strace
Trace system calls and signals
8.6. ltrace
Trace library calls
9. Debugging
9.1. gdb
r[un]execute the whole programs[tart]execute and stop at the start of main functionframe [N],f [N]see and change stack frame (going in and out of function context)info,ishow informationbbreakpointlocalslocal variablesargsCLI arguments
s[tep]execute one line of the source codec[ontinue]execute until a breakpointfinishrun until the current function returnsuntil Nrun until the lineNbr Nset a breakpoint
C-x 2 rotates through the TUI.
9.2. coredumpctl
Linux kernel stores the coredump as specified by
/proc/sys/kernel/core_pattern.
Kernel often alegate the handling of coredump file to the systemd-coredump.
Which can be controled by coredumpctl
listinfo MATCHdump MATCHdebug MATCHrungdbby default
If MATCH is not specified, the last coredump is used.
9.3. ulimit
Get or set file size limit
$ ulimit -c should return unlimited for the coredump to work?