Standard Libraries and You: Why care at all?

#include <help_me,_c_library.h>

When a programmer writing C and C++ code "#include"s system files like <stdlib.h>, <math.h> and <string.h>, a collection of types, macros, and functions are compiled and used alongside his/her programs. Where does this code come from?

For Linux programmers, writing C and C++ code means interacting with the underlying operating system in pretty direct ways. When user-space code interrupts to the kernel with different values in %eax, the kernel will provide a mechanism to interact with the world in an interesting yet primitive way. These calls include opening files, reading and writing simple character buffers, forking new processes, allocating virtual memory, and so much more.

Though system calls provide a powerful interface, they are extremely basic (the calls must be done through assembly), and programming using raw system calls would be a disastrous case of "re-inventing the wheel" -- can you imagine re-writing malloc every time you want dynamic memory? Or re-writing a thread-spawning function to have a multi-threaded program? Though this is technically a possibility, it is a bad idea: re-writing such a large amount of functionality is both unnecessary and error-prone for most applications. Furthermore, it would be extremely difficult to help develop a partially developed application which uses an non-standard library: imagine a world with a vastly different interface to printf (and all other non-system call functions which you expect to have).

Glibc, an example Standard C Library, interacting with system calls and user applications. [Source]
At this point, hopefully I've convinced you of a couple things:

  1. You are probably already using a standard library when writing your code.
  2. This is a good thing.

However, this isn't the full story. There is no single standard library, but rather, there are multiple libraries which try to accomplish a similar function, each with their own intricacies and flavors. In my attempt to paint a broad picture, I will describe a few of the well-known libraries, with a focus on how they are different from each other.

glibc [source]

One of the most well-known standard libraries, glibc is often synonymous with "standard library" when making a C program which compiles with gcc. Considered to be one of the most feature-complete standard libraries, glibc has survived decades of testing and development. However, glibc has some downsides: first, it is considered bloated, as it includes many extensions of debatable usage (many of which are non-standard), and secondly, it is tightly coupled with the gcc compiler.

musl [source]

A newer standard library, musl attempts to improve on glibc in many practical ways: musl has a smaller codebase than glibc, provides better error handling, is arguably faster, and supposedly more compliant with C++11. Unfortunately, musl does not support as many architectures as glibc, and some non-standard glibc functionality does not work through musl.

Bionic [source]

Developed by Google for Android in 2008, Bionic is the standard library of choice for the Android operating system. Designed for low-memory, slower frequency devices, Bionic acts like a trimmed down glibc with certain components redeveloped from scratch, such as pthreads and the dynamic linker.

newlib [source]

Although glibc is the most common standard library for desktop Linux, Newlib is a standard library which focuses on the use case of embedded systems. Generally considered to be more operating system independent than other standard libraries, newlib includes support for a large number of architectures, with a focus on compatibility.