How to Generate Hexdumps Using mulle-buffer: A Complete Guide

The mulle-buffer library provides built-in hexdump functionality via mulle_buffer_hexdump() and mulle_buffer_hexdump_line() functions, offering configurable output with offset, hexadecimal values, and ASCII columns through bit-flag options defined in src/mulle-buffer.h.

The mulle-c/mulle-buffer repository delivers a flexible C library for dynamic buffer management that includes a production-ready hexdump facility. This feature renders binary data in the classic "offset | hex | ASCII" format without requiring external tools or dependencies. Whether you are inspecting network packets, debugging serialized data, or analyzing memory dumps, you can generate formatted hexdumps directly to any output sink supported by the buffer abstraction.

The Hexdump API Architecture

The hexdump implementation consists of a configuration enum and two core functions distributed across the main header and implementation files.

Configuration Options

The enum mulle_buffer_hexdump_options declared in src/mulle-buffer.h (lines 1930–1944) defines bit-flags that control output formatting:

  • mulle_buffer_hexdump_default – prints offset, hexadecimal values, and ASCII representation
  • mulle_buffer_hexdump_no_offset – suppresses the address column
  • mulle_buffer_hexdump_no_ascii – suppresses the printable character column

Core Functions

  1. mulle_buffer_hexdump_line – Defined in src/mulle-buffer.c (lines 30–68), this function renders a single 16-byte line respecting the option flags. It writes the offset (if enabled), up to 16 hexadecimal byte pairs with spacing, and the pipe-delimited ASCII representation.

  2. mulle_buffer_hexdump – Defined in src/mulle-buffer.c (lines 71–101), this function iterates over the entire byte range and calls mulle_buffer_hexdump_line for each 16-byte block. It handles line counting, buffer advancement, and newline insertion.

How the Hexdump Implementation Works

Internally, the facility processes data in fixed 16-byte chunks to match standard hexdump conventions. When you invoke mulle_buffer_hexdump(), the function calculates the number of full lines required and delegates rendering to mulle_buffer_hexdump_line() for each segment.

The line renderer performs three distinct write operations via mulle_buffer_advance() and mulle_buffer_add_byte():

  1. Offset column – Writes an 8-digit hexadecimal address (e.g., 00000000) unless suppressed by mulle_buffer_hexdump_no_offset
  2. Hexadecimal values – Writes space-separated byte pairs (e.g., 48 65 6c 6c 6f), padding with spaces when the line contains fewer than 16 bytes
  3. ASCII representation – Writes a pipe character followed by printable characters or dots for non-printable bytes (0x00–0x1F and 0x7F–0xFF), unless suppressed by mulle_buffer_hexdump_no_ascii

Because all output operations use the generic buffer append routines, the dump can target any flushable buffer type, including FILE* wrappers, string buffers, or custom memory sinks.

Generating Your First Hexdump

Follow this workflow to dump buffer contents to standard output:

#include <mulle-buffer/mulle-buffer.h>
#include <stdio.h>

int main(void)
{
    mulle_buffer_do( dump )
    {
        mulle_buffer_do( src )
        {
            /* Fill source buffer with sample data */
            for( unsigned int i = 0; i < 256; ++i )
                mulle_buffer_add_byte( src, (uint8_t)i );

            /* Output to stdout using a flushable FILE buffer */
            mulle_flushablebuffer_do_FILE( out, stdout )
            {
                mulle_buffer_hexdump( out,
                                     mulle_buffer_get_bytes( src ),
                                     mulle_buffer_get_length( src ),
                                     0,                                /* start offset */
                                     mulle_buffer_hexdump_default );   /* all columns */
            }
        }
    }
    return 0;
}

This pattern mirrors the reference implementation in test/buffer/hexdump.c (lines 12–44), which validates both default and compact output modes.

Customizing Output with Bit Flags

The options parameter accepts bitwise combinations, allowing precise control over the output format.

Suppress the ASCII column:

mulle_buffer_hexdump( out,
                     mulle_buffer_get_bytes( src ),
                     mulle_buffer_get_length( src ),
                     0,
                     mulle_buffer_hexdump_no_ascii );

Generate a raw hex-only dump:

unsigned int opts = mulle_buffer_hexdump_no_offset | mulle_buffer_hexdump_no_ascii;
mulle_buffer_hexdump( out, data, length, 0, opts );

Specify a non-zero start address:

Useful when dumping a slice of a larger file or memory region. Pass the base address as the fourth parameter:

size_t base_address = 0x1000;
mulle_buffer_hexdump( out, data, length, base_address, mulle_buffer_hexdump_default );

This renders the offset column starting at 00001000 rather than 00000000.

Complete Working Examples

Minimal string dump:

#include <mulle-buffer/mulle-buffer.h>
#include <string.h>
#include <stdio.h>

int main(void)
{
    const char *msg = "Hello, mulle-buffer!";
    
    mulle_buffer_do( src )
    {
        mulle_buffer_add_bytes( src, msg, strlen(msg) );
        
        mulle_flushablebuffer_do_FILE( out, stdout )
        {
            mulle_buffer_hexdump( out,
                                 mulle_buffer_get_bytes( src ),
                                 mulle_buffer_get_length( src ),
                                 0,
                                 mulle_buffer_hexdump_default );
        }
    }
    return 0;
}

Expected output:


00000000  48 65 6c 6c 6f 2c 20 6d  75 6c 6c 65 2d 62 75 66  |Hello, mulle-buf|
00000010  66 65 72 21                                    |fer!           |

Compact mode without ASCII:

mulle_buffer_hexdump( out, bytes, length, 0, mulle_buffer_hexdump_no_ascii );

Output:


00000000  48 65 6c 6c 6f 2c 20 6d  75 6c 6c 65 2d 62 75 66  
00000010  66 65 72 21                                            

Summary

  • The hexdump facility resides in src/mulle-buffer.h (enum options) and src/mulle-buffer.c (implementation)
  • mulle_buffer_hexdump() renders complete dumps while mulle_buffer_hexdump_line() handles individual 16-byte rows
  • Control output columns using bitwise combinations of mulle_buffer_hexdump_no_offset and mulle_buffer_hexdump_no_ascii
  • All output operations use the buffer abstraction, supporting files, strings, or custom sinks
  • Specify alternative start addresses to dump memory slices with correct offset labels

Frequently Asked Questions

How do I suppress the ASCII column in mulle-buffer hexdumps?

Pass mulle_buffer_hexdump_no_ascii as the options argument to mulle_buffer_hexdump(). This flag is defined in src/mulle-buffer.h and instructs the renderer to omit the pipe-delimited character column, printing only offsets and hexadecimal values.

Can I change the starting offset address in the hexdump output?

Yes. Supply the desired base address as the fourth parameter (start counter) to mulle_buffer_hexdump(). For example, passing 0x100 begins the offset column at 00000100 instead of 00000000, which is useful when dumping segments of larger binary files.

What output destinations are supported by mulle_buffer_hexdump?

Any destination compatible with the library's buffer abstraction. The examples use mulle_flushablebuffer_do_FILE() to target stdout, but you can write to string buffers, memory regions, or custom flushable implementations. The function writes via mulle_buffer_advance() and mulle_buffer_add_byte(), ensuring compatibility with all buffer types.

Where are the hexdump functions defined in the source code?

The public API and option enum are declared in src/mulle-buffer.h (lines 1930–1944). The implementation of mulle_buffer_hexdump_line() appears in src/mulle-buffer.c (lines 30–68), while mulle_buffer_hexdump() is defined immediately after in the same file (lines 71–101). Reference usage appears in test/buffer/hexdump.c.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →