How can I get a string from a pointer inside a cfunc?

Hi there. I have an issue where I need to create a callback function that accepts a void pointer to char array, extracts the content of the array and prints to screen for debugging purposes.

So far, I’ve managed to do the following

import numpy as np
from numba import cfunc, carray, types
import ctypes

import numpy as np
from numba import cfunc, carray, types
import ctypes

str_ = "Hello World!".encode('utf-8')
ptr_ = ctypes.cast(ctypes.c_char_p(str_), ctypes.c_void_p)
sig = types.int8(types.voidptr, types.int8)

@cfunc(sig)
def get_string_from_ptr(ptr_, index):
    s=carray(ptr_, 1, types.int8)
    return s[index]

string_ = ""

for i in range(len(str_)):
    val = get_string_from_ptr.ctypes(ptr_, i)
    string_ += chr(val)

print(string_)

this lets me print each character outside of the c-func one-by-one, if I iterate over the index of the array. Strangely, if I print any of the values inside get_string_from_ptr, for example

@cfunc(sig)
def get_string_from_ptr(ptr_, index):
    s=carray(ptr_, 1, types.int8)

    print(s[0])

the program hangs. So I can’t actually do anything with the string inside the c-wrapped function.

I’m sorry for all these questions, but numba’s documentation about this particular library is very limited, and I have not found any posts on the forum that discusses this usecase.

Thank you

Answering my own post: it seems you cannot even print a value from a @cfunc decorated function:

from numba import types, cfunc

@cfunc(types.void())
def print_fun():
   print(2)

# does not work
print_fun.ctypes()

but this works:

@cfunc(types.void())
def printfun():
    print("2")

printfun.ctypes()

so the issue seems to be on the side of the print function when called from a cfunc decorated function. Do I need to use a different approach to print then?

I found a workaround, by wrapping the standard printf function from the c-library I was able to print the string by reference:

import numpy as np
from llvmlite import binding
from numba import cfunc, carray, types, njit
import ctypes
from ctypes.util import find_library


binding.load_library_permanently(find_library("c"))

str_ = "Hello World!".encode('utf-8')
ptr_ = ctypes.cast(ctypes.c_char_p(str_), ctypes.c_void_p)

printf = types.ExternalFunction("printf", types.void(types.voidptr))

@cfunc(types.void(types.voidptr))
def printf_(string_ptr):
    printf(string_ptr)

printf_.ctypes(ptr_)

prints “Hello World!”. I guess that’s useful if you want to print dynamically…