C Programming Tips (2022)

Ángel Ortega

This is a compilation of the C language programming tips I posted on the Fediverse during 2022:

The elvis operator

https://triptico.com/social/angel/p/1673265846.832608

If you program in C, you've probably used what is called the ternary operator a million times in expressions like this:

value = user_value ? user_value : default_value;

Where you test user_value and, if it's non-zero, you store it in value; otherwise, you set value to default_value.

What you may not know is that, thanks to a gcc (and others) extension, you can abridge that expression to this:

value = user_value ?: default_value;

This ?: thing is colloquially named the 'Elvis' operator (if you don't see why, just look at it with you head slightly slanted to the left).

https://en.wikipedia.org/wiki/Elvis_operator

Linker optimization

https://triptico.com/social/angel/p/1672111113.792792

TIL that there is something named linker optimization that forces the deletion of unused functions in your final executable. As a bonus, you get the list of unused functions as compiler warnings (dead code is always bad, so you get the change to delete them or comment them out).

If you have a standard build system, do the following:

make CFLAGS="-ffunction-sections -fdata-sections" LDFLAGS="-Wl,--gc-sections -Wl,--print-gc-sections"

Concatenated PPM images as a video stream

https://triptico.com/social/angel/p/1671347271.960902

TIL that most video processing tools accept as a valid input stream a set of concatenated PPM [1] files, so you can generate video from your own programs easily. You just have to pipe your program's output to the appropriate tools (indicating the FPS) like

./fancy-prg | mpv --no-correct-pts --fps=$FPS -

or

./fancy-prg | ffmpeg -i - -r $FPS video.mp4
[1] Netpbm format (Wikipedia)

Full paths in shared libraries' soname

https://triptico.com/social/angel/p/1667714202.685173

TIL that you can have a full-path soname in a dynamic library, so that binaries linked to it can find it even if it's in a non-standard place:

gcc -shared -o libcrazy.so -Wl,-soname,/an/esoteric/place/to/store/libcrazy.so crazy.c
gcc -o main -L. -lcrazy main.c

This way, you don't need kludges regarding the use of LD_LIBRARY_PATH nor anything else.

Executing hand-crafted machine code

https://triptico.com/social/angel/p/1667464895.428412

If you want to create an executable program in memory and execute it without going through the filesystem, this is how you do it (Linux only):

int fd = memfd_create("foo", MFD_CLOEXEC);
// write your image to fd however you want
fexecve(fd, argv, envp);
https://unix.stackexchange.com/questions/230472/can-i-exec-an-entirely-new-process-without-an-executable-file

Finding memory leaks

https://triptico.com/social/angel/p/1667328755.759676

If you develop in C, you'll probably end up using memory leak detection tools like valgrind, libleak or the scan-build tool from the LLVM compiler. There is a less known tool inside the GCC compiler itself: the -fsanitize=address.

If you use a standard make setup, you can recompile your project doing

make CFLAGS="-fsanitize=address -fno-omit-frame-pointer"

After exiting your program, a summary of memory leak errors (including the line of the source code were it happened) will be printed out.

Poor man's profiler

https://triptico.com/social/angel/p/1665694300.323309

Poor man's profiler, or profiling a running program with a cheap combination of gdb, awk and scripting:

Sampling tools like oprofile or dtrace's profile provider don't really provide methods to see what [multithreaded] programs are blocking on - only where they spend CPU time. Though there exist advanced techniques (such as systemtap and dtrace call level probes), it is overkill to build upon that [...]

[...] one needs to improvise, like.. use debuggers - they can walk threads and provide stacks.

http://poormansprofiler.org/

Fast character case conversion

https://triptico.com/social/angel/p/1666985574.734641

Fast character case conversion (or how to really compress sparse arrays):

Converting strings and characters between lower and upper cases is a very common need.

In particular, case conversion is often used to implement case-insensitive comparision, an operation that is often present on the program's fast paths as a part of data container lookups and content manipulation.

So it is usually desirable to make case conversions as fast as possible.

In this post we are going to look at one of the options - very fast case conversion using compressed lookup tables and also at some options for compressing these even further.

https://github.com/apankrat/notes/tree/master/fast-case-conversion

gdb surprises

https://triptico.com/social/angel/p/1667549267.231691

TIL by accident that you can type make from inside gdb and does what you think it does.

Modern C for C++ Peeps

https://triptico.com/social/angel/p/1673121099.281843

I find the article interesting not only for C++ "peeps", but for us greybeard C programmers as well, who learnt the language in the eighties. Remarkable sections in the document are:

https://floooh.github.io/2019/09/27/modern-c-for-cpp-peeps.html