# tezc/sc: twenty-three C libraries you copy one file at a time

> A collection of standalone C99 data structures and utilities, each in its own directory as a header and source pair, with no build step and a README that tells you to read the code before updating it.

**tezc/sc** — Common libraries and data structures for C.

- Repository: https://github.com/tezc/sc
- Stars: 2,571 · Forks: 298
- Language: C
- License: BSD-3-Clause
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/tezc-sc

## One directory per library, one header and source pair

The README states the model in two sentences: each folder is stand-alone with a single header and source pair in it, and there is no build for libraries, just copy files you want. The example given is the logger, where you copy sc_log.h and sc_log.c into your project. That is the whole distribution mechanism, described elsewhere in the README as drag and drop source code distribution.

There are twenty-three entries in the library table, and the repository tree matches them one for one: array, buffer, condition, crc32, disjoint, heap, ini, linked-list, logger, map, memory-map, mutex, option, perf, queue, sc, signal, socket, string, thread, time, timer and uri. That correspondence is worth noting because it means the tree is a reliable index: anything you see listed is a directory you can open, and there is no hidden dependency between them.

The table descriptions are terse and unusually honest about scope. The array is a generic array or vector. The buffer is for encoding and decoding variables, described as best fit for protocol and serialization implementations. The heap is a min heap that can be used as a max heap or priority queue. The queue is generic and can serve as a deque, stack or list. The option module is a command line argument parser, and the README calls it a very basic one.

Two of the implementations stand out for using specific hardware or algorithms. The crc32 module is crc32c and uses the crc32c CPU instruction when available, which turns a checksum into a near-free operation on the processors that have it. The timer is a hashed timing wheel implementation with fast poll and cancel operations, which is the right structure when you have many timers rather than a few.

## The CMakeLists.txt sitting next to a README that denies there is a build

Two statements about building sit side by side in this repository, and neither cancels the other. The README says there is no build for libraries and that you just copy the files you want. The repository tree contains a root `CMakeLists.txt`, plus a `.clang-format`, a `codecov.yml` and a `.github/` directory.

Both are consistent with the rest of the project once you understand what the CMake file is for. A consumer that wants the test suites, the sanitizers or the coverage reporting configured through CI needs an entry point, and that is what a root CMakeLists provides. It does not make the libraries installable units with headers under a prefix, which is what the README is telling you not to expect. The README's own distribution claim is a source file you copy, and nothing in the tree contradicts that.

So the practical reading is: treat the individual directories as the unit of reuse and ignore the build system unless you are working inside the project. If you are a consumer, `array/sc_array.h` plus `array/sc_array.c` is your entire integration cost, and the CMake file is noise you never need to read.

The only other project-level file worth naming is `LICENSE`, which sits alongside the README and matches both the BSD badge and the BSD-3-Clause licence GitHub reports for the repository. Licensing is one of the few things about this collection that requires no interpretation.

## Releases stopped in 2021 while the README says to use master

The README answers the release question like this: please use the master branch, because it is considered stable. GitHub reports three published releases for this repository: v1.0.2 on 2021-02-19, v1.0.3 on 2021-02-27 and v1.0.4 on 2021-03-23, each with a release body that is nothing but the version number. So there is a semantic version line, it stopped five years ago, and the author tells you to ignore it.

Put that next to the answer on API stability: please don't expect a stable API. The reasoning is given and it is a fair one. These libraries are quite small, most of them less than a few hundred lines of code, and the idea is that you read the code, understand what it does, and adapt it. The author says you should not update the libraries blindly, expects you to handle API differences easily, and promises to do his best to keep the API stable without committing to it.

This is the single most important thing to understand about the project before you adopt anything from it. There is no version constraint that means what it means for a normal library. A v1.0.4 tag tells you almost nothing about the current state of the code, because the interesting work happens on master and the tags stopped in 2021. If you vendor these files, pin the copy in your own tree and take responsibility for it, which is what the design already requires of you.

Activity is real rather than abandoned: GitHub reports the last push on 2026-07-18, 2,574 stars, 297 forks and only 3 open issues. Three open issues on a project of this size says either that the author closes things quickly or that few people file bugs, and either way it is not the profile of an abandoned repository.

## What the test and sanitizer matrix actually covers

The README claims high performance with minimal memory usage, portability between many operating systems and architectures, tests with 100% branch coverage, and multiple sanitizers. The second claim is the one with numbers attached, and the numbers are worth reading carefully:

```yaml
OS         : Linux, MacOS, FreeBSD and Windows  
Compilers  : GCC, Clang, MSVC  
Arch       : x64, aarch64, armv6(32 bit), armv7(32 bit), ppc64le, s390x(big endian), riscv64  
Sanitizers : valgrind and clang/gcc sanitizers(address, undefined, thread)
```

That is four operating systems, three compilers and eight architectures, including a big-endian target in s390x. A big-endian architecture in the matrix is the entry that matters most, because most hobby C code has an accidental endianness assumption in it somewhere, and a CI matrix containing s390x is a reasonable signal that the byte-level modules, buffer and string and crc32, have been forced to get that right.

The sanitizer coverage is equally broad: address, undefined behaviour and thread sanitizers from both clang and gcc, plus valgrind. For libraries that wrap condition variables, mutexes and sockets for POSIX and Windows, thread sanitizer coverage is the difference between a wrapper that mostly works and one that does not have a race in it.

The branch coverage claim comes with a codecov badge in the README, and the repository contains both the badge configuration and a `.github/` directory, so the CI story is at least wired up. The README does not claim the code is bug free, and the Q&A section makes the opposite point about production use, so read 100% branch coverage as a statement about test density rather than correctness.

## The author's own answers on taste, API churn and optimization

The README ends with a Q&A section that is more informative than most feature lists, because it is where the author explains what kind of project this is and what he expects from users.

On whether the libraries are better than another library, the answer is deliberately not a benchmark. He often uses these for high performance server-side applications, cares about readable and easy to debug code, and describes the collection as showing his own trade-offs about performance, API design and readability. You may or may not like it. That is a fair framing for a personal library, and it tells you the selection criteria were taste, not a survey of alternatives.

On why an API is not changed to be easier, the answer is that better APIs are possible for generic libraries if you do not care about undefined behaviour, and that he tries to avoid it. Send a pull request, but be sure it does not introduce undefined behaviour. Combined with the no-stable-API promise, this tells you the acceptance bar for a change: correctness first, convenience second.

On the most efficient way to use the libraries, the advice is short: add them to your project as source files and ideally compile with optimization and link-time optimization plus profile-guided optimization.

```bash
-O3 -flto + PGO
```

The author adds that this may not make any difference for your use case, which is the right caveat.

Two answers are worth repeating verbatim in spirit. On whether library X is used in a product, the answer is that some libraries are used in production but you should always test yourself. And on whether the code is production ready, the posture throughout is that you own the copy. For a collection of a few hundred lines per library, that is the correct division of responsibility.

## What the list covers and what it deliberately leaves out

The twenty-three modules cluster into three groups, and the boundaries are informative.

Data structures proper: array as a generic array or vector, linked list as an intrusive linked list, heap as a min heap usable as a priority queue, queue as a generic queue usable as a deque, stack or list, map as a high performance open addressing hashmap, disjoint as a disjoint set, also known as Union-Find, with amortized fast search, and timer as the hashed timing wheel. That is a coherent container set, and the interesting detail is that the map is open addressing rather than chaining, which suits a cache-conscious style.

Abstraction layers over the operating system: condition, mutex and thread as Posix and Windows wrappers, time, memory map as an mmap wrapper, socket covering pipes, TCP and Unix domain sockets with Epoll, Kqueue and WSAPoll, and signal as signal safe snprintf plus a signal handler that handles Ctrl+C and prints a backtrace on crash. These are the modules that would otherwise be duplicated in every project, and having one implementation that runs on both POSIX and Windows is the portability claim in practice.

Parsing and formatting: ini as an ini parser, uri as a basic URI parser, option as the command line parser, buffer for encoding and decoding, string as length prefixed, null terminated C strings, crc32, and logger. Also perf, a benchmark utility that reaches performance counters through `perf_event_open`, which is Linux-specific and therefore the one module that does not travel.

What is absent matters as much. There is no JSON parser, no TLS, no event loop abstraction, no string formatting library beyond `sc` utilities and the signal-safe variant, no date or calendar handling, and nothing for async I/O beyond socket polling. The map entry also notes that no separate map name is needed for a tree structure, and the option module is explicitly basic.

Judged against a general purpose C library, the gaps are large. Judged as a server-side collection of small, auditable, well-tested components that you read before adopting, the gaps are the point.

## Conclusion

tezc/sc is a personal standard library rather than a dependency, and reading it that way is the only way to use it well. The value is in the density: a hashed timing wheel, an open addressing hashmap, a crc32c that uses the CPU instruction when available, and a signal-safe formatter, each small enough to audit in one sitting. What it is not is infrastructure, since there is no event loop abstraction, no serialization format, no TLS, and no compatibility promise, which the README states plainly when it tells you not to update the libraries blindly. Where to start: pick the one directory you actually need, read the header, and copy the pair into your tree rather than wiring up a package manager around it.

## FAQ

### How do I use tezc/sc libraries in my project?

Copy the single header and source pair for the library you want into your project, for example sc_log.h and sc_log.c for the logger. There is no build step for the libraries and no package to link against; the README describes the distribution as drag and drop source code.

### Are tezc/sc library APIs stable?

No, and the README says so explicitly. It asks you not to expect a stable API, to read the code and adapt it to your needs, and not to update the libraries blindly. The author promises to keep the API stable where he can but does not commit to it, and published tags stopped at v1.0.4 in 2021.

### Which platforms does tezc/sc run on?

The README lists CI coverage for Linux, MacOS, FreeBSD and Windows with GCC, Clang and MSVC, across x64, aarch64, armv6, armv7, ppc64le, s390x big endian and riscv64. Sanitizers listed are valgrind plus the address, undefined and thread sanitizers from clang and gcc. The perf module is the exception, since it uses Linux perf_event_open.

### What data structures does tezc/sc include?

The list covers a generic array or vector, an intrusive linked list, a min heap that can act as a priority queue, a generic queue that can act as a deque or stack, a high performance open addressing hashmap, a disjoint set with amortized fast search, and a hashed timing wheel for timers. Each lives in its own directory as a header and source pair.

## Sources

- [Issues](https://github.com/tezc/sc/issues)
- [License: BSD-3-Clause](https://github.com/tezc/sc/blob/master/LICENSE)
- [README](https://github.com/tezc/sc/blob/master/README.md)
- [Releases](https://github.com/tezc/sc/releases)
- [tezc/sc on GitHub](https://github.com/tezc/sc)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/tezc-sc
