Dealing with C strings usually involves asking "Who owns this memory?"
In Perl, strings are values. In C, they are pointers. A common (though not thread-safe) pattern in C libraries is to return a pointer to an internal static buffer. This buffer is overwritten or freed the next time the function is called.
If you were using raw pointers, this would be dangerous; your Perl variable would suddenly change its value or point to freed memory when you made a subsequent API call.
Affix solves this by copying string return values into Perl's memory space immediately.
The Recipe
In this example, we implement a C function that remembers its last result. It frees the old result before allocating a new one. We use a final call with undef to trigger a cleanup.
use v5.40;
use Affix qw[:all];
use Affix::Build;
# 1. Compile the C library
my $c = Affix::Build->new();
$c->add( \<<~'END', lang => 'c' );
#include <stdlib.h>
#include <string.h>
const char * string_reverse(const char * input) {
// Static pointer persists across function calls
static char * output = NULL;
int i, len;
// Cleanup previous call's memory
if (output != NULL) {
free(output);
output = NULL;
}
// Handle "Cleanup Mode" (NULL input)
if (input == NULL)
return NULL;
// Allocate new buffer
len = strlen(input);
output = malloc(len + 1);
// Reverse the string
for (i = 0; input[i]; i++)
output[len - i - 1] = input[i];
output[len] = '\0';
return output;
}
END
my $lib = $c->link;
# 2. Bind the function
# String means "const char*" for input and output.
affix $lib, 'string_reverse', [String] => String;
# 3. Use it
# Input: "\nHello world"
# Output: "dlrow olleH\n"
print string_reverse("\nHello world");
# 4. Cleanup
# Passing undef sends NULL to C, triggering the free() logic.
string_reverse(undef);
How It Works
-
1. Passing Strings (Input)
[ String ] => ...When passing a Perl string to a
Stringargument, Affix temporarily allocates a C buffer, copies the Perl string (encoded as UTF-8), and passes that pointer to C. This buffer is valid only for the duration of the call. -
2. Returning Strings (Output)
... => StringWhen a C function returns a
Stringtype, Affix reads the memory at that address (up to the first null byte), creates a new Perl scalar containing those bytes, and returns the scalar.It does not return a pointer to the C memory.
This is crucial for this recipe. Even though the C function eventually calls
free(output)on the next invocation, our Perl variable holding"dlrow olleH\n"remains safe because it is a distinct copy. -
3. Passing Undef
string_reverse(undef);For string arguments,
undefis marshalled asNULL. Our C function checks for this to perform its cleanup duties.
Kitchen Reminders
-
Copy vs. Reference
If you want a copy of the text (standard Perl behavior), use the type
String. If you want to modify the C memory buffer in place or hold onto the specific memory address, usePointer[Char](see Chapter 3). -
Thread Safety
While Affix is thread-safe, C functions using
staticvariables (like the one in this recipe) are generally not thread-safe. If two threads callstring_reverseat the same time, they will race to free/overwrite the same static pointer.