Some C functions don't have a fixed number of arguments. The most famous example is printf, which takes a format string and... almost everything else. Affix supports variadic functions, but they require a little more care than standard functions because the C compiler isn't there to cast types for you.

The Recipe

We will wrap the standard C library's snprintf. This is safer than printf because it writes to a buffer.

We also handle a common cross-platform annoyance: on Windows, this function is often named _snprintf, while on Linux/macOS it is snprintf. We can normalize this using symbol aliasing.

use v5.40;
use Affix;

# 1. Bind snprintf
# Windows uses _snprintf, POSIX uses snprintf.
# We detect the OS and bind the correct symbol to the name 'snprintf'.
my $symbol = ( $^O eq 'MSWin32' ? '_' : '' ) . 'snprintf';

# Signature: int snprintf(char *str, size_t size, const char *format, ...);
# We use '...' (or VarArgs) to indicate the variadic part.
affix libc, [ $symbol => 'snprintf' ], [ Pointer [Char], Int, String, VarArgs ] => Int;

# 2. Prepare a buffer
# We need a place for C to write the formatted string.
my $size   = 100;
my $buffer = "\0" x $size;

# 3. Call with Inference
# Affix guesses the C type based on the Perl value.
#   "A String" -> char*
#   123        -> int64_t
#   12.34      -> double
snprintf( $buffer, $size, 'Name: %s, ID: %d, Score: %.2f', 'Alice', 42, 99.9 );

# Clean up the null terminator and print
$buffer =~ s/\0.*//;
say $buffer;    # "Name: Alice, ID: 42, Score: 99.90"

# 4. Explicit Coercion
# Sometimes inference isn't enough.
# Here we want to print a pointer address (%p).
# Passing a Perl integer might be interpreted as a value, not a pointer.
# We use coerce() to force specific types.
my $ptr = 0xDEADBEEF;
snprintf( $buffer, $size, 'Pointer address: %p', coerce( Pointer [Void], $ptr ) );
say $buffer =~ s/\0.*//r;

How It Works

Kitchen Reminders