Introduction to NextStd
Welcome to the official documentation for NextStd—the safer, modern alternative to the traditional C standard library.
For decades, C developers have relied on <stdio.h>, <string.h>,
and <stdlib.h>. While incredibly fast, these legacy libraries are
fundamentally unsafe. A single mismatched %d in a printf, a missing
\0 in a string, or a silent NULL pointer can trigger catastrophic
Segmentation Faults, buffer overflows, and security vulnerabilities.
NextStd fixes this at the foundation.
By combining the elegant simplicity of C11 macros on the frontend with the mathematically proven memory safety of Rust on the backend, NextStd delivers a zero-compromise development experience.
Core Pillars of NextStd
- Type-Safe I/O: Never write a format specifier again. NextStd uses C11
_Genericmacros to automatically route data types at compile time. - Crash-Proof Control Flow: Replace silent failures and dangerous
gotostatements with Python-styleNS_TRYandNS_EXCEPTmacros. - Immunity to NULL: Every FFI boundary rigorously checks for
NULLpointers. Passing bad memory to NextStd gracefully returns an error code instead of killing your program. - Modern String Memory: Strings are powered by Small String Optimization (SSO), meaning short text costs zero heap allocations, and massive text safely catches Out-Of-Memory (OOM) errors without panicking.
Who is this for?
NextStd is built for C developers, systems programmers, and embedded engineers
who want the safety guarantees of a modern language without actually having to
rewrite their entire codebase in Rust. It compiles down to a standard static or
dynamic C library (.a, .so, .dylib, or .dll) and links identically t
o any standard C dependency.
Ready to upgrade your C code?
Navigate through this book using the sidebar to the left. We recommend starting with Why NextStd? for a deeper dive into the architectural philosophy, or jumping straight into Getting Started to write your first safe program!
Why NextStd?
C is the undisputed language of the physical and systems world. Whether you are building real-time camera processing pipelines, writing constrained firmware for microcontrollers like the ESP32 and RP2040, or crafting lightning-fast terminal applications, C gives you the raw, uncompromised control you need.
But that control comes with a massive, decades-old hidden cost: The Standard Library.
The Legacy C Trap
Libraries like <stdio.h>, <string.h>, and <stdlib.h> were designed
in an era before cybersecurity was a primary concern. Today, they are
the root cause of the majority of software vulnerabilities.
Consider a standard C input operation:
int age;
printf("Enter your age: ");
scanf("%d", &age);
If a user types "twenty" instead of 20, scanf silently fails,
leaves the invalid text in the input buffer (corrupting future reads),
and leaves age uninitialized. If you try to concatenate two strings using
strcat and miscalculate the buffer size by a single byte, you trigger a
buffer overflow. If you pass a NULL pointer into strlen, your entire
system crashes with a Segmentation Fault.
In mission-critical environments, a single uncaught NULL pointer can brick a
device or crash a production system.
The Rewrite Dilemma
The modern industry answer to C’s unsafety is to rewrite everything in Rust.
Rust is incredible. It mathematically proves memory safety at compile time. However, rewriting massive, established C codebases, or trying to interface Rust with highly specific hardware vendor SDKs, is often unrealistic, expensive, and time-consuming.
Developers shouldn’t have to abandon their C codebases just to get modern safety guarantees.
The NextStd Bridge
NextStd was built to be the bridge. It is a drop-in systems library that brings the fearless safety of Rust directly into C, using standard Foreign Function Interface (FFI) boundaries.
With NextStd, you don’t rewrite your C code; you just upgrade your tools.
- You keep your C compiler, your Makefiles, and your existing architecture.
- You replace dangerous functions like
printfandscanfwithns_printandns_read. - You gain compile-time type routing,
NULLpointer immunity, safe heap allocation, and Python-styleTRY/EXCEPTerror handling.
By handling the most dangerous operations (I/O, string manipulation, and dynamic memory) in a memory-safe backend, NextStd allows you to write C code that is fundamentally immune to standard library footguns.
You get the speed of C, with the peace of mind of Rust.
Safety Guarantees
When we say NextStd is “safe,” we aren’t just talking about compiler warnings or best practices. We are talking about architectural guarantees enforced at the Foreign Function Interface (FFI) boundary between C and Rust.
Here are the core vulnerability classes that NextStd entirely eliminates from your C codebase.
1. Null Pointer Immunity (No More Segfaults)
In standard C, passing a NULL pointer to strlen() or strcpy() results in
immediate Undefined Behavior, typically manifesting as a fatal Segmentation
Fault.
NextStd actively intercepts bad memory. Every single FFI boundary function in
the library checks for NULL before performing any operations. If a NULL
pointer is detected, the operation is safely aborted, and an NS_ERROR_ANY code
is returned for your NS_TRY block to catch gracefully.
2. Out-of-Memory (OOM) Protection
Standard C’s malloc returns NULL when the heap is exhausted—a condition
developers frequently forget to check. Standard Rust, on the other hand, will
panic and instantly crash the program when an allocation fails.
NextStd takes the safe middle path. It uses Rust’s try_reserve API for all
dynamic heap allocations. If the system runs out of memory (a critical threat in
embedded and constrained environments), NextStd safely catches the failure and
returns an NS_ERROR_STRING_ALLOC code without crashing your process.
3. Buffer Overflow Prevention
C strings are notoriously dangerous null-terminated (\0) arrays. If you forget
the terminator, or use strcat into a buffer that is even one byte too small,
you silently overwrite adjacent memory.
NextStd uses a length-prefixed struct combined with Small String Optimization (SSO). The exact length of the string is always known. If a string needs to grow beyond its 24-byte inline capacity, NextStd automatically and safely requests exactly the right amount of heap memory. Buffer overflows are mathematically impossible by design.
4. Format String Vulnerabilities
Using printf("%d", "text") forces the C compiler to trust the developer
blindly. If the format specifier doesn’t match the variable type, the program
reads garbage memory from the stack or crashes entirely.
NextStd leverages C11 _Generic macros to completely eliminate this class of
bugs by routing types at compile time:
int age = 21;
ns_string name; // Assume initialized
ns_println(age); // Automatically routes to ns_print_int
ns_println(name); // Automatically routes to ns_print_string
Because there are no format strings, format string vulnerabilities simply cannot exist.
Getting Started with NextStd
Welcome to the practical side of NextStd. Up to this point, we have covered the philosophy and the safety guarantees. Now, it is time to actually write some code.
Integrating a Rust-backed static or dynamic library into a C project might sound intimidating, but standard tooling makes the process incredibly straightforward. Because NextStd exposes a standard Foreign Function Interface (FFI) boundary, your C compiler treats it exactly like any other legacy C library.
Note: Alpha Stage Development > Because NextStd is currently in active Alpha, standalone integration (moving the headers and
.afiles to a completely separate C project) requires manual linker configuration. For the smoothest experience right now, we highly recommend working directly inside the cloned NextStd project directory and utilizing the providedexamples/folder and Makefile!
The Integration Workflow
Working within the NextStd repository follows a simple workflow:
-
Build the Backend: First, compile the Rust source code into a static archive (
.a). We’ve wrapped Cargo in our Makefile, so you just need to run:make rust -
Write Your C Code: Create a new
.cfile inside theexamples/directory. Since you are in the project folder, you can simply include the core headers using relative paths:#include "../include/ns.h" #include "../include/ns_error.h" -
Link and Compile: Instead of running raw
gcccommands and manually linking the Rust archive, use the built-in Makefile. You can view all available example targets by running:make list(To build and run a specific example, just type
makefollowed by the filename without the.cextension, e.g.,make 01_hello_world!)
Prerequisites
Before moving forward with the installation, ensure your development environment has the required tools installed:
- A C Compiler:
gccorclang(or a cross-compiler if you are targeting embedded systems). - The Rust Toolchain: You need
cargoandrustcinstalled to build the backend. (Available via rustup.rs). - Make: To run the build scripts that seamlessly tie the Rust backend and C frontend together.
What’s Next?
Use the sidebar to navigate through the setup process:
- Installation & Linking: Step-by-step instructions for compiling the backend and connecting it to your C project.
- Your First Program: Write, compile, and run your first memory-safe NextStd application.
- Build System Integration: Learn how to seamlessly
integrate NextStd into your
MakefileorCMakeLists.txtfor automated builds.
Installation & Linking
Since NextStd is currently in active Alpha, the easiest and most reliable way to use the library is to clone the repository directly and work within its provided directory structure. Our build system handles the complexities of cross-language linking for you.
Here is how to get your environment set up in under two minutes.
Step 1: Clone the Repository
First, grab the latest version of the NextStd source code from GitHub:
git clone https://github.com/NextStd/NextStd.git
cd NextStd
Step 2: Build the Rust Backend
NextStd’s core logic is written in Rust. Before you can compile any C code that
uses the library, you need to compile the Rust source into a static C library
archive (.a).
We have provided a unified Makefile at the root of the project to handle this.
Simply run:
make rust
What is happening behind the scenes? This command invokes Cargo (Rust’s
package manager) to build the workspace in release mode. The Rust compiler
(rustc) takes all the modules in the crates/ directory, heavily optimizes
them, and outputs a highly performant static archive file.
Step 3: Verify the Installation
To ensure everything compiled correctly and your C compiler can successfully link against the new Rust backend, let’s run one of the pre-configured examples.
Type the following command into your terminal:
make 01_hello_world
(Note: Do not include the .c extension when using the make command!)
If everything is configured correctly, your C compiler will grab
examples/01_hello_world.c, link it against the Rust backend, and execute the
resulting binary. You should see a safely printed greeting in your terminal!
Advanced: Standalone Linking (Manual)
While we highly recommend working inside the cloned repository during the Alpha phase, you can use NextStd in an external, standalone project.
If you choose to do this, you must manually copy the include/ directory and
the libns.a file to your project. Furthermore, because libns.a contains Rust
code, you must explicitly link the C system libraries that the Rust standard
library depends on.
A typical GCC compilation command for a standalone project looks like this:
gcc main.c -L/path/to/libns_directory -lns -lpthread -ldl -lm -o my_safe_program
-L: Tells the compiler where to find the library.-lns: Links the NextStd archive.-lpthread,-ldl,-lm: Standard system libraries required by the Rust backend. (Note: These specific flags are for Linux; EndeavourOS, Arch, or other distributions will use these exact flags, while macOS or Windows MinGW may require slightly different ones).
Your First Program
Now that your environment is set up and the Rust backend is compiled, let’s write your first memory-safe C program using NextStd.
We are going to replace the traditional, unsafe printf function with NextStd’s
type-safe ns_println macro.
The Basic Program
If you are working inside the cloned repository, create a new file named
hello.c inside the examples/ directory.
Add the following code to print basic text and variables:
#include "../include/ns.h"
int main() {
// 1. Printing a standard string
ns_println("Hello, World! Welcome to NextStd.");
// 2. Printing an integer safely without format specifiers
int version = 1;
ns_print("NextStd Version: ");
ns_println(version);
// 3. Printing a floating-point number
double pi = 3.14159;
ns_print("Value of Pi: ");
ns_println(pi);
return 0;
}
To compile and execute this program, open your terminal in the root of the
NextStd repository and run:
make hello
Adding Terminal Colors
NextStd also provides a dedicated, cross-platform color module to help you build beautiful CLI tools. You don’t need to remember ANSI escape codes; you just include the header and use the macros.
Create a second file named hello_color.c in your examples/ directory:
#include "../include/ns.h"
#include "../include/ns_color.h" // Import the color macros
int main() {
// Printing with a specific color and resetting it afterward
ns_println(NS_COLOR_GREEN "Success: System initialized safely." NS_COLOR_RESET);
// Combining styles like bold text with colors
ns_println(NS_COLOR_CYAN NS_COLOR_BOLD "NextStd is running..." NS_COLOR_RESET);
// Warning and Error colors
ns_println(NS_COLOR_YELLOW "Warning: Low memory." NS_COLOR_RESET);
ns_println(NS_COLOR_RED "Error: Connection lost." NS_COLOR_RESET);
return 0;
}
Compile and run this exactly like the first one:
make hello_color
How It Works
If you are coming from standard C, the code above might look like magic. How
does ns_println know whether to print a string, an integer, or a double
without you typing %s, %d, or %f?
NextStd leverages C11’s _Generic keyword to inspect the type of the variable
at compile time. It then automatically routes your data to the correct,
memory-safe Rust backend function (e.g., ns_print_int, ns_print_double, or
ns_print_str).
Because there are no format strings, there is zero risk of mismatched types causing undefined behavior or reading garbage memory from the stack. If you try to print a type that NextStd doesn’t support yet, the compiler will safely throw an error before the program ever runs.