In C, arrays and pointers are cousins. In function arguments, they are twins. Declaring void func(int a[]) is exactly the same as void func(int *a). However, in Perl and thus in Affix, this isn't the case.
Pointer[Int]expects a reference to a scalar integer (memory address).Array[Int]expects a list of integers (data).
This recipe shows how to pass lists of data to C using the Array type, which handles allocation and copying for you.
The Recipe
We will wrap a C function that sums a zero-terminated array of integers.
use v5.40;
use Affix qw[:all];
use Affix::Build;
# 1. Compile C
my $c = Affix::Build->new();
$c->add( \<<~'END', lang => 'c' );
#include <stdlib.h>
int array_sum(const int * a) {
int i, sum;
if (a == NULL)
return -1; // Error code for NULL
// Loop until we hit a 0
for (i = 0, sum = 0; a[i] != 0; i++)
sum += a[i];
return sum;
}
END
# 2. Bind
# We use Array[Int] to tell Affix to expect a list of numbers.
# Affix handles the C "array decay" (passing as pointer) automatically.
affix $c->link, array_sum => [ Array [Int] ] => Int;
# 3. Call
# Pass undef -> NULL
say "Undef: " . array_sum(undef); # -1
# Pass [0] -> {0} -> Sums to 0 (Immediate stop)
say "Zero: " . array_sum( [0] ); # 0
# Pass List -> {1, 2, 3, 0} -> Sums to 6
say "List: " . array_sum( [ 1, 2, 3, 0 ] ); # 6
How It Works
-
1. Array marshalling
array_sum( [ 1, 2, 3, 0 ] );When you define an argument as
Array[Int], Affix allocates a temporary C array, copies the values from your Perl array reference into it, and passes the pointer to the C function. This matches C's array decay rules. -
2. The
undefcasearray_sum(undef);C allows array pointers to be
NULL. Affix supports this by checking forundefand passingNULLto the function, skipping the allocation entirely.
Kitchen Reminders
-
Syntactic sugar
You could have bound this function using
Pointer[Int]. If you did, you would have to manually pack a binary string or usemallocto create the buffer.Array[Int]handles that boilerplate for you. -
Sentinels
Notice we passed
0at the end of our list:[1, 2, 3, 0]. Affix does not automatically append null terminators to numeric arrays (unlike Strings). Since our C function relies on finding a0to stop the loop, we must provide it explicitly. I could have designed this demonstration to accept aSize_tarray length but this seemed like a better lesson to sneak in here.