Skip to content

NAME

clibx_print - lightweight printf implementation using direct Linux syscalls

SYNOPSIS

#include \<clibx/print.h>

DESCRIPTION

clibx_print is a completely standalone, optional module providing a minimal printf-style output implementation using direct Linux x86_64 syscalls. It has no dependencies on libc\'s stdio, making it useful for minimal environments or educational purposes.

This module is independent and can be used without clibx.h.

FUNCTIONS

void clibx_printf(const char *fmt, ...)

: Printf-style output to stdout (file descriptor 1). Supports format specifiers listed in the SUPPORTED SPECIFIERS section. Returns void. Write failures are not reported to the caller; silent failures occur on syscall errors.

void clibx_fprintf(int fd, const char *fmt, ...)

: Printf-style output to an arbitrary file descriptor. Accepts the same format specifiers as clibx_printf. Returns void. Write failures are not reported to the caller; silent failures occur on syscall errors.

SUPPORTED SPECIFIERS

TABLE

EXAMPLE

#include <clibx/print.h>

int main(void) {
    clibx_printf("Hello, %s!\n", "World");
    clibx_printf("Age: %d, Score: %u\n", 30, 100);
    clibx_printf("Hex: 0x%x, Octal: %o\n", 255, 82);

    int arr[] = {1, 2, 3};
    clibx_printf("Array at: %p\n", (void*)arr);

    clibx_fprintf(2, "Error: %s (code: %d)\n", 
                  "Something failed", 404);

    return 0;
}

COMPILATION

Link with no additional libraries:

gcc myprogram.c -o myprogram

PLATFORM REQUIREMENTS

Architecture

: x86_64 (Intel/AMD 64-bit)

Operating System

: Linux with syscall support

Kernel

: Standard Linux kernel with write(2) syscall

LIMITATIONS

No Floating Point

: %f, %F, %e, %E, %g, %G specifiers are not supported. Floating-point formatting would require significant code overhead.

No Width/Precision

: Modifiers like ., -, 0 (padding), width specifiers are not implemented. Formatting is straightforward: types are printed with default representation.

No %n Specifier

: The %n specifier (write count) is not supported for security reasons.

Basic %p Implementation

: Pointers are printed in lowercase hex with 0x prefix.

NULL String Handling (%s)

: When %s is used with a NULL pointer, no output is produced (unlike standard printf which prints \"(null)\"). Caller should ensure non-NULL strings are passed.

WHY USE CLIBX_PRINT?

Minimal Dependencies

: Zero dependency on libc\'s stdio. Perfect for freestanding environments.

Direct Syscalls

: Uses Linux write(2) directly via inline assembly. No buffering, each call writes immediately to the file descriptor.

Educational Value

: Useful for learning about syscall-level I/O in C.

Small Footprint

: Extremely lightweight, suitable for embedded or minimal programs.

Independent Module

: Can be used standalone without clibx.h or other dependencies.

IMPLEMENTATION DETAILS

Linux write() Syscall

: Uses inline x86_64 assembly with the System V AMD64 ABI:

    mov $1, %%rax          /* Syscall number for write(2) */
    syscall                /* Invoke syscall */

Register mapping: rdi = fd, rsi = buf, rdx = count. Return value in rax (bytes written or error code).

No Buffering

: Each call to clibx_printf or clibx_fprintf immediately invokes write(2). No internal buffer is maintained. Each format specifier results in one or more syscalls.

Error Handling

: The public API does not expose syscall return values. Write failures are silent. If write(2) returns an error code (negative value), it is not reported or handled. Caller cannot detect write failures or partial writes. Passed file descriptors are not validated; invalid fds cause silent write failures.

EXAMPLE: USING WITH STDERR

#include <clibx/print.h>

int main(void) {
    clibx_fprintf(1, "Normal output\n");      /* stdout */
    clibx_fprintf(2, "Error message\n");      /* stderr */

    return 0;
}

EXAMPLE: MINIMAL PROGRAM (NO LIBC STDIO)

#define _GNU_SOURCE
#include <clibx/print.h>

int main(void) {
    clibx_printf("Hello from syscalls!\n");
    clibx_printf("Numbers: %d, %u, 0x%x\n", -1, 42, 255);
    return 0;
}

/* Compile with minimal libc:
   gcc -nostdlib minimal.c -o minimal \
       /lib64/crt1.o /lib64/crti.o /lib64/crtn.o \
       -lc -dynamic-linker /lib64/ld-linux-x86-64.so*
 */

COMPARISON WITH STANDARD PRINTF

TABLE

NOTES

When to Use

: Use clibx_printf when you specifically need direct syscall output without stdio buffering or libc overhead. For most applications, standard printf is more appropriate and feature-complete.

When NOT to Use

: Do not use for production code requiring error handling or reliability. As write failures are silent, this is unsuitable for applications that need to detect I/O errors. Standard printf or other I/O libraries are recommended for robust I/O.

File Descriptors

: Standard file descriptors: 0 = stdin, 1 = stdout, 2 = stderr. You can write to any open file descriptor (must be already open). Invalid or closed file descriptors result in silent failures.

Unicode/Multibyte

: No special handling of UTF-8 or multibyte characters. Bytes are written directly to the file descriptor.

Performance

: Syscall overhead per format specifier may be significant for high-frequency logging. Consider buffering or batching output for performance-critical code.

Format Specifier Parsing

: Format string is parsed linearly. Invalid format specifiers are printed literally. Example: clibx_printf(\"%q\n\") will print \"%q\" to output.

SEE ALSO

clibx(3), clibx_ll(3), write(2), printf(3)

AUTHOR

David Balishyan \<davidbalishyan12@gmail.com>

BUGS

Report bugs to the project repository.

LICENSE

See LICENSE file in the project root.