val is a zero-dependency library that implements a dynamic val_t type for C programs via NaN-boxing. It can store:
- IEEE-754 double-precision floats
- Signed and unsigned 52-bit integers (as double)
- Typed pointers (void, char, custom pointers)
- Booleans,
nil(and the nil-family constantsvalnone,valundefined,valtombstone,valdeleted), and user-defined constants - Pairs (a 16-bit and a 32-bit value in one word)
- Stored strings (library-owned strings, via
vallib)
All in one 64-bit word, with efficient runtime checks, comparisons, and hashing.
| OS | compiler | notes |
|---|---|---|
| Linux | gcc 11.4.0 | 64-bits and 32-bits targets |
| Linux | clang 14.0.0 | 64-bits and 32-bits targets |
| MS Windows 11 | Mingw64 15.1.0 | 64-bits and 32-bits targets |
| MS Windows 11 | MS cl 19.44 | /std:C11 |
-
Compact representation: 64-bit
val_tuses NaN payload bits. -
Fast type checks: Macro utilities like
valisnumber(),valisinteger(),valisptr(),valisbool(),valisnil(). -
Generic constructors:
val_t v1 = val(3.14); // A double val_t v2 = val(-42); // A signed integer val_t v3 = val("hello"); // A string
-
Generic extractor:
double d = valtodouble(v1); int64_t i = valtoint(v2); char *s = valtoptr(v3);
-
Comparison & hashing:
valcmp(a,b)returns –1, 0, or 1.valhash(a)produces a 32-bit FNV1a or Murmur-style hash.
-
Pairs:
valpair(l,r)packs a 16-bit and a 32-bit value in one word. -
Data structures (in
vallib): a vec used as a dynamic array, stack, queue, or map withval_tkeys — plus sorting, searching, and library-owned stored strings. -
Zero dependencies: just include
val.hin any C11/C17 project (data structures needvallib.h+vallib.c). -
Extensible: define additional pointer-tags or constants via macros.
The project ships as two layers — pick the one that matches your needs:
Core only — val.h (header-only). If you only need the val_t type and
its value operations (boxing, type checks, comparison, hashing, string
conversion, pointers, constants, pairs), copy val.h into your project's
include directory and include it. No build steps, no linking, no heap
allocation — val.h is a pure single-file header.
#include "val.h"Full library — vallib.h + vallib.c. For the data structures
(valvec, stacks, queues, maps), sorting and searching, library-owned stored
strings, and library-managed buffers, also copy vallib.h and vallib.c,
include vallib.h, and compile and link vallib.c with your sources:
#include "vallib.h"cc myprog.c vallib.c -o myprogvallib.h includes the whole core, so a program that links vallib.c gets
both layers. As a rule of thumb: if you don't use any allocating function,
val.h alone is enough; if you need vectors, maps, stored strings, or
growable buffers, use vallib.
#include <stdio.h>
#include "val.h"
int main(void) {
// Create various values
val_t d = val(2.71828);
val_t i = val(-12345);
val_t u = val((unsigned int)12345);
val_t b = val((_Bool)true);
val_t s = val("NaN-boxing");
// Type checks
assert(valisnumber(d));
assert(valisint(i));
assert(valisint(u));
assert(valisbool(b));
assert(valischarptr(s));
// Conversions
printf("double: %f\n", valtodouble(d));
printf("signed: %lld\n", (long long)valtoint(i));
printf("unsigned: %llu\n", (unsigned long long)valtounsignedint(u));
printf("bool: %s\n", valtobool(b) ? "true" : "false");
printf("string: %s\n", (char *)valtoptr(s));
// Comparison
val_t x = val(10);
val_t y = val(20);
printf("cmp(x,y) = %d\n", valcmp(x,y)); // –1
// Note that in `valcomp()`, `10` is automatically converted to `val_t`
printf("cmp(x,10) = %d\n", valcmp(x,10)); // 0
// Hashing
printf("hash(\"NaN-boxing\") = 0x%x\n", valhash(s));
return 0;
}See the docs directory for full documentation.
The test directory is also a source of valuable information.
- NaN-Boxing Overview Piotr Duperas, “NaN boxing or how to make the world dynamic” https://piotrduperas.com/posts/nan-boxing
- Nanobox Implementation Viktor Söderqvist, nanbox.h (zuiderkwast) https://github.com/zuiderkwast/nanbox/blob/master/nanbox.h
- Interpreter Optimization Robert Nystrom, Crafting Interpreters, Chapter “Optimization” https://craftinginterpreters.com/optimization.html
- IEEE 754 & Architecture Manual Intel® 64 and IA-32 Architectures Software Developer’s Manual, Vol 1 §4.2.2, Table 4-3
© 2025 Remo Dentato ‹rdentato@gmail.com› Released under the MIT License.