Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 _Generic macros to automatically route data types at compile time.
  • Crash-Proof Control Flow: Replace silent failures and dangerous goto statements with Python-style NS_TRY and NS_EXCEPT macros.
  • Immunity to NULL: Every FFI boundary rigorously checks for NULL pointers. 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 printf and scanf with ns_print and ns_read.
  • You gain compile-time type routing, NULL pointer immunity, safe heap allocation, and Python-style TRY/EXCEPT error 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 .a files 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 provided examples/ folder and Makefile!

The Integration Workflow

Working within the NextStd repository follows a simple workflow:

  1. 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
    
  2. Write Your C Code: Create a new .c file inside the examples/ 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"
    
  3. Link and Compile: Instead of running raw gcc commands 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 make followed by the filename without the .c extension, 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: gcc or clang (or a cross-compiler if you are targeting embedded systems).
  • The Rust Toolchain: You need cargo and rustc installed 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 Makefile or CMakeLists.txt for 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.

Build System Integration

Error Handling (ns_error)

The Try/Except Macros

Null Pointer Protection

Error Codes Reference

Input & Output (ns_io)

Safe Printing (ns_print)

Safe Reading (ns_read)

Terminal Colors

Strings (ns_string)

Small String Optimization (SSO)

Creating & Freeing Strings

String Concatenation

Examples

Safe User Input

Building a CLI Menu

String Manipulation

Contributing

Architecture Overview

Adding New Modules