Skip to content

Latest commit

 

History

History
749 lines (568 loc) · 20.4 KB

cpp.md

File metadata and controls

749 lines (568 loc) · 20.4 KB

+

explain

ast

repl

gdb /bin/true -ex 'b main' -ex 'r'
printf 'int main(){}' | gcc -o /tmp/1 -x c - && gdb /tmp/1 -ex 'b main' -ex 'r'

building

# Optional: Outputs `configure`
autoreconf -fi
./configure
make
sudo make install
# ||
./configure --prefix="$HOME/foo"
# ||
make prefix="$HOME/foo" install

pkgconfig

  • PKG_CONFIG_PATH set to path containing .pc files

position-independent code

gcc -fPIE -pie
# vs.
gcc -no-pie -fno-pic

32bit vs 64bit binary

  • IA-32, a variant of x86, commonly known as i386 (the name used by Debian) or i686 (which, like IA-32, are generations of the x86 architecture series)
  • x86-64, also known as x64 or amd64 (the name used by Debian) (not to be confused with IA-64 which is completely different)
od -An -t x1 -j 4 -N 1 foo
# Output: 01 if 32bit, 02 if 64bit

References:

following syscall references in libc

name mangling, name decoration

# GCC / Clang
c++filt
# MSVC
undname '?func1@a@@AAEXH@Z'
# Watcom
# https://github.com/open-watcom/open-watcom-v2/blob/master/bld/lib_misc/c/demangle.c
demangle 'W?h$n(i)v'

debug info

strip - removes symbol names

language servers - clangd

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON

# || From build commands
# References: https://github.com/rizsotto/Bear
bear make

# vscode
bear -a -o .vscode/compile_commands.json make
# c_cpp_properties.json
# "compileCommands": "${workspaceFolder}/.vscode/compile_commands.json"

# Validation
test -f compile_commands.json

compiler

testing

printf '#include<stdio.h>
int main() { puts("Hi!"); return 0; }' \
    | i686-linux-musl-gcc -xc - \
    && ./a.out; rm -f a.out

includes, libraries

# create shared library
gcc foo.c -o foo -shared -fPIC

# validate paths
ld "-L$HOME/opt/libunwind/src/.libs" -lunwind --verbose 2>&1 | grep succeeded

# linking shared library
gcc -L. -lfoo foo.c -o foo
LD_RUNTIME_PATH=. ./foo
# ||
gcc -L. -lfoo -Wl,-rpath,$PWD foo.c -o foo
./foo

# override dynamic linking behaviour, e.g. link libfirst.a and libsecond.so:
gcc -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond

# override system shared libraries
./configure LDFLAGS="-Wl,-rpath,$HOME/opt/libunwind/src/.libs -L$HOME/opt/libunwind/src/.libs"

# both c and c++
./configure \
    LDFLAGS="-L/foo/usr/lib" \
    CPPFLAGS="-I/foo" \
    CPATH="/foo"

# only c
./configure \
    CFLAGS="-I/foo" \
    C_INCLUDE_PATH="/foo"

# only c++
./configure \
    CXXFLAGS="-I/foo" \
    CPLUS_INCLUDE_PATH="/foo"

# include library `libfoo.so.*`
LIBS=-lfoo ./configure

# include specific library version
LIBS=-l:libfoo.so.123 ./configure

# debug
less ./config.log

# workaround for "/usr/include/linux/errno.h:1:10: fatal error: 'asm/errno.h' file not found"
ln -s /usr/include/asm-generic /usr/include/asm

MinGW GCC support

reimp.exe -d foo.lib
dlltool.exe -k -d foo.def -l foo.a

override include

On /include/foo.h:

#include "foo.h"
#include "bar.h"

CPPFLAGS="-I/include"

guards

https://stackoverflow.com/questions/31115366/make-error-multiple-definitions-of-despite-include-guard

GNU extensions

https://stackoverflow.com/questions/10613126/what-are-the-differences-between-std-c11-and-std-gnu11

static build

# With configure
./configure LDFLAGS=-static
env CXXFLAGS=-static --enable-static --disable-shared -fPIC --prefix="$(pwd)" make

# With pkg_config
LDFLAGS="-static" PKG_CONFIG="pkg-config --static" ./configure --disable-shared --enable-static
make -j4 V=1 LDFLAGS="-static -all-static"

# With configure (cross-compile)
CC=$HOME/share/toolchains/aarch64-linux-musl-cross/bin/aarch64-linux-musl-gcc ./configure --host=aarch64-linux-musl LDFLAGS=-static

# With Makefile (cross-compile)
make CC=./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc LDFLAGS=-static
./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc -O -Wall -std=c90 -c hello.c
./mips64-linux-musl-cross/bin/mips64-linux-musl-gcc -static -o hello hello.o

# With QEMU (cross-compile)
docker run --platform linux/arm64 -it -v "$HOME/share:/share:z" arm64v8/alpine:3.22.0
  • musl
    docker run -it -v "$HOME/share:/share:z" alpine:3.22.0
    
    # From package sources
    # References:
    # - https://unix.stackexchange.com/questions/496755/how-to-get-the-source-code-used-to-build-the-packages-of-the-base-alpine-linux-d
    # - https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package
    # - https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
    # - https://moebuta.org/posts/compiling-static-binaries-with-alpine/
    apk update
    apk add --no-cache alpine-sdk autoconf automake binutils binutils-dev byacc elfutils-dev flex gawk gcc gettext gettext-dev libtool libnl3-dev linux-headers musl-dev sudo
    cd /opt
    git clone --depth 1 --branch v3.22.0 git://git.alpinelinux.org/aports
    # Build
    app=
    cd /opt/aports/main/"$app"
    # Override pkg-config dependencies (e.g. when specifying static libs)
    # References: [Static compilation errors \- tmux 2\.9, ncurses 6\.1, libevent 2\.1\.8 · Issue \#1729 · tmux/tmux · GitHub](https://github.com/tmux/tmux/issues/1729)
    # export PKG_CONFIG=/bin/true
    export PKG_CONFIG='pkg-config --static'
    # [Edit APKBUILD to include `-static` in CFLAGS / `LDFLAGS="-static" ./configure` / `make LDFLAGS="-static -all-static"`]
    # [For curl: https://github.com/moparisthebest/static-curl/blob/master/build.sh]
    # [For strace: ~/share/alpine/static/strace613.sh]
    echo | abuild-keygen -a -i
    abuild -Fcr
    # Unpack
    tar -xzvf /root/packages/main/x86_64/"$app".apk
    cp "$app" /share/
    # ||
    cp ./pkg/strace/usr/bin/"$app" /share/
    strip /share/"$app"
  • Unsupported in libtool

tooling


gdb

https://github.com/CppCon/CppCon2018/blob/master/Presentations/liberating_the_debugging_experience_with_the_gdb_python_api/liberating_the_debugging_experience_with_the_gdb_python_api__jeff_trull__cppcon_2018.pdf

uses ptrace

info signals when to stop, print, pass to inferior handle SIGINT stop print nopass

thread apply all backtrace full

gdbserver localhost:2000 ./a.out target remote localhost:2000

reverse debugging

b main
b _exit
command 1
record
command 2
run

reverse-stepi

rr replay

watchpoints

watch foo stop when foo is modified watch -l foo watch location rwatch foo stop when foo is read watch foo thread 3 stop when thread 3 modifies foo watch foo if foo > 10 stop when foo is> 1O

Dynamic Printf

Use dprintf to put printf's in your code without recompiling. e.g. dprintf mutex_lock,"m is %p m->magic is %u\n",m,m->magic

Control how the printfs happen:

set dprintf-style gdb|call|agent set dprintf-function fprintf set dprintf-channel mylog

errno

print *((int*(*)())__errno_location)()

valgrind

Cachegrind: cache profiler. simulates l1, D1, L2 caches Callgrind: like cachegrind, but also with call-graphs Massif: heap profiler Helgrind: find race conditions in multithreaded programs DRD: Data Race Detector. Like Helgrind, but uses less memory. Lackey / None: demo/unit test of valgrind itself.


out-of-bounds

-fsanitize=address

https://devblogs.microsoft.com/cppblog/finding-bugs-with-addresssanitizer-msvc-compiler/

typo key initialization

foo(const map<string, string>& bar)
map::at()

temporary default values

-fsanitize-address-use-after-scope

synchronization with volatile

std::atomics, mutex

unbuffered stream

setbuf(stdout, NULL);

thread safety

shared_ptr<T>
    ok: reference count, control block
    ko: T
    ko: shared_ptr pointers

atomic<shared_ptr>

shadow declaration

// RAII types + default constructor
std::string(foo);

// -Wshadow
// good but ko: -Wshadow-compatible-local
unique_lock<mutex> g(m_mutex);

RAII

// Second argument is a pointer to the type of std::fclose, we could also have
// written it out explicitly as std::unique_ptr<FILE, int (*)(FILE*)>.
using FilePtr = std::unique_ptr<FILE, decltype(std::fclose) *>;

// Instantiate the FILE* with the destructor we want.
FilePtr file(std::fopen(filename, "rbe"), std::fclose);

// Do stuff with the file
std::fread(buf_.data(), 1, buf_.size(), file.get());

auto

int i = 0;
auto p = &i; // int*
auto* p = &i; // still int*

In C, &x types at T* for some T, where T is the decayed type of the lvalue x. therefore, T = int, so T* = int*. therefore p must have type int*. The type inference "flows" from the value on the right to the type. If auto is there alone, everything is inferred. If you add a , it ensures the value is a pointer to an inferred type. & creates a pointer, auto constrains the possible values. changes auto to infer the rest of type of the value on the right side of assignment after it's established that the value is a pointer. The same way * in int* a = b; requires b to be a pointer and requires it to be a pointer to int. auto is not a type, it's a constraint. let p : Pointer = &i // int* let p : Pointer = &i // auto* let p = &i // auto

unpack

// struct.pack('>f', 225.22).hex()
int i = 0x43613852;
float f = *((float*)&i);
printf("225.22 = %.2f\n", f);

Dependencies

vcpkg

https://vcpkg.readthedocs.io/en/latest/

conan

conan info .. conan search gtest -r conan-center

Decentralized servers

  • OSS, corporate, private, etc Central cache on local PC
  • sharing of the dependencies data among different projects Support for
  • sources only (do not use prebuilt binaries even if available)
  • sources + prebuilt binaries (improves build performance)
  • binaries only (for closed source projects and development tools) Offline use

space-efficient algorithms

heavy hitters, majority element, boyer-moore's majority vote elements that occur at least x% of the time e.g. throttle users with multiple requests

morris traversal O(1) space tree traversal e.g. free children without recursion

reservoir sampling given a stream of data, select k items at random e.g. biggrep

HyperLogLog count number of distinct elements by leading zeros, partition input space, apply harmonic mean

STL

#include <algorithm>

adjacent_find partitions partial_sort ~= nth_element + sort rotate gather = 2 stable_partition, pair inserted in point set_difference

stable

preserve prior ordering whenever there is a conflict e.g. priority queue for same values

comparison

https://en.wikipedia.org/wiki/Sorting_algorithm#Comparison_of_algorithms

bjam

sudo dnf install -y boost-build boost-devel boost-jam boost-python3-devel python3-devel sudo ln -fs /usr/bin/bjam /usr/bin/b2 sudo ln -fs /usr/lib64/libpython3.7m.so /usr/lib64/libpython3.7.so source ~/code/sand/boost-build/profile.sh

debug

#define protected public
#define private public
#define final
#include <foo.h>

assert state has not changed between function calls

windows

# crosscompiling from linux to 32-bit exe
i686-w64-mingw32-gcc foo.c -lws2_32 -o foo.exe
# crosscompiling from linux to 64-bit exe
x86_64-w64-mingw32-gcc foo.c -lws2_32 -o foo.exe

https://virtuallyfun.com/wordpress/2020/02/01/cross-compiling-sdl-1-2-15-for-arm-win32/

C:\proj\ss\SDL-1.2.15\VisualC\SDL>link /dll -out:sdl.dll *.obj winmm.lib dxguid.lib gdi32.lib user32.lib advapi32.lib dxguid.lib uuid.lib dxguid.lib Version.res
Microsoft (R) Incremental Linker Version 14.24.28315.0
Copyright (C) Microsoft Corporation. All rights reserved.

Creating library sdl.lib and object sdl.exp
SDL_dx5events.obj : error LNK2001: unresolved external symbol GUID_SysMouse
strings ~/Downloads/dxguid.lib | grep GUID_SysMouse
# Output:
# _GUID_SysMouse

https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.16299.0/um/dinput.h#L117

DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00);

https://github.com/tpn/winsdk-10/blob/master/Include/10.0.10240.0/shared/guiddef.h#L59

#ifndef DECLSPEC_SELECTANY
#if (_MSC_VER >= 1100)
#define DECLSPEC_SELECTANY  __declspec(selectany)
#else
#define DECLSPEC_SELECTANY
#endif
#endif

// ...

#ifdef INITGUID
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    EXTERN_C const GUID DECLSPEC_SELECTANY name \
        = { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
#else
#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
    EXTERN_C const GUID FAR name
#endif // INITGUID

https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=vs-2019 https://stackoverflow.com/questions/2284610/what-is-declspec-and-when-do-i-need-to-use-it

=> define INITGUID

case studies

IOCCC's Best Abuse of the Rules in 1988 c #include "/dev/tty" > it waits for you to type c code at your terminal, then compiles that. /dev/tty is the device representing the current terminal and can be read or written like a regular file - https://twitter.com/eevee/status/678720136061169664

build issues

Undefined reference `__powf_finite` with clang 9.0.1, Linux 5.5.4-arch1-1 and glibc 2.31-1 · Issue #2146 · google/filament · GitHub c - What exactly is -fno-builtin doing here? - Stack Overflow Audacity &#8211; New Major Release &#8211; Compile Fix, for Portaudio.. &#8211; Adventures With Linux ™

early exit bugs

mutex.lock();
// ...
if (foo) {
    return; // missed unlock call
}
// ...
mutex.unlock();

undefined behaviour

Qt

connect(manager, SIGNAL(finished(QNetworkReply*)), this,
                 SLOT(replyFinished(QNetworkReply*)));

void NetworkHandler::replyFinished(QNetworkReply *reply) {
  qDebug() << reply->readAll();
}

void debugRequest(QNetworkRequest request, QByteArray data = QByteArray()) {
  qDebug() << request.url().toString();
  const QList<QByteArray>& rawHeaderList(request.rawHeaderList());
  foreach (QByteArray rawHeader, rawHeaderList) {
    qDebug() << request.rawHeader(rawHeader);
  }
  qDebug() << data;
}

linked libraries

ldd /bin/true
LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux-x86-64.so.2 /bin/true

# https://github.com/ncopa/lddtree
objdump -x /bin/true | grep NEEDED
readelf -d /bin/true | grep NEEDED

triplet

gcc -dumpmachine

format