I have a C library that provides and array and another library providing function that takes an array in the form of a pointer, line this:
// first library (doesn't have a header)
const uint32_t some_array_size = 303530;
const uint8_t some_array[303530] = { … }
// second library (has a header)
void some_func(const uint8_t *buf, size_t buf_len);
I'd like to importc both of these things and pass the array to the function, like this:
let some_array_size: cint {.importc.}
let some_array: ??? {.importc.}
proc some_func(buf: ???, buf_len: cint) {.importc, header: "some_library.h".}
some_func(some_array, some_array_size)
What types should I use so that this works properly?
@griffith1deady is right, ptr UncheckedArray is the way to go. What this means is basically just that Nim won't make any bounds checks to see if access to this array is valid or not. This is similar to C where, even given a strict definition as above, array access is purely a runtime error. Also the declaration const uint8_t some_array[303530] basically just means that 303530 elements of uint8_t size should be allocated on the stack, and some_array holds a pointer to this array (which is the same as a pointer to the first element in C). So your examples become:
let some_array_size: cint {.importc.}
let some_array: ptr UncheckedArray[uint8] {.importc.}
proc some_func(buf: ptr UncheckedArray [uint8], buf_len: cint) {.importc, header: "some_library.h".}
some_func(some_array, some_array_size)
Unfortunately there is no way to express the const modifier properly in Nim, but you'll get errors from the C compiler if you violate this constraint. Of course I'd always recommend using automatic wrapping with Futhark where possible. Although if you don't have a header (??) it might get tricky. You could of course write a valid header file yourself.
Why type of some_array_size in your C code and Nim code are different? Also type of buf_len parameter in C code and Nim code are different.
Here is working code set:
clibfunc.h:
#include <stddef.h>
void cfunc(int* buf, size_t buflen);
clibfunc.c:
#include <stdio.h>
#include "clibfunc.h"
void cfunc(int* buf, size_t buflen) {
for(size_t i = 0; i < buflen; ++i) {
printf("%d\n", buf[i]);
}
}
clibarry.c:
#include <stddef.h>
const int carray[] = {12345, 54321};
const size_t carrayLen = sizeof(carray) / sizeof(carray[0]);
test.nim:
{.compile: "clibfunc.c".}
{.compile: "clibarry.c".}
{.emit: """extern const int carray[];
extern const size_t carrayLen;
""".}
let
carrayLen {.importc, nodecl.}: csize_t
carray {.importc, nodecl.}: ptr cint
proc cfunc(buf: ptr cint; buflen: csize_t) {.header: "clibfunc.h".}
cfunc(carray, carrayLen)
Compile:
$ nim c -r test.nim
You may use addr.
let some_array_size {.importc.}: uint32
let some_array {.importc.}: array[303530, uint8]
proc some_func(buf: ptr uint8, buf_len: csize_t) {.importc, header: "some_library.h".}
some_func(addr(some_array[0]), csize_t(some_array_size))