# Calling a C function pointer passed as argument to @cfunc

**URL:** <https://numba.discourse.group/t/calling-a-c-function-pointer-passed-as-argument-to-cfunc/1601>\
**Category:** Support: How do I do ...?\
**Created:** [October 15, 2022, 1:37am UTC](https://numba.discourse.group/t/calling-a-c-function-pointer-passed-as-argument-to-cfunc/1601 "2022-10-15T01:37:39Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![nelson2005](https://yyz2.discourse-cdn.com/free1/user_avatar/numba.discourse.group/nelson2005/32/47_2.png) [@nelson2005](https://numba.discourse.group/u/nelson2005)\
**Post date:** [October 15, 2022, 1:37am UTC](https://numba.discourse.group/t/calling-a-c-function-pointer-passed-as-argument-to-cfunc/1601/1 "2022-10-15T01:37:39Z")

</div>

I have a ‘real’ C function like

```nohighlight
int64_t cpp_func(int64_t a, int64_t b) {
    return a * b;
}

```

that I want to call from a @cfunc that receives the address to cpp\_func like

```python
@numba.cfunc(numba.int64(numba.int64, numba.int64, voidptr))
def forward(a, b, c_address):
    return c_address(a, b) # what can I write here to call the external C function? I know the signature but not the address at compile time.

```

I think this is somewhat similar but different from [previous](https://numba.discourse.group/t/how-to-call-the-externel-c-function-in-ir/1477) [discussions](https://numba.discourse.group/t/passing-functions-as-arguments-to-a-cfunc/792).

I’ve poked about a fair bit on the net, haven’t really found anything terribly useful. This is also similar to @DannyWeitekamp’s [casting a raw pointer to structref](https://numba.discourse.group/t/any-numba-equivalent-for-casting-a-raw-pointer-to-a-structref-dict-list-etc/351) except the target is an external C function and I lack the lowering chops to figure it out.

---

<div class="post-metadata">

**Author:** ![DannyWeitekamp](https://yyz2.discourse-cdn.com/free1/user_avatar/numba.discourse.group/dannyweitekamp/32/144_2.png) [@DannyWeitekamp](https://numba.discourse.group/u/DannyWeitekamp)\
**Post date:** [October 15, 2022, 5:17am UTC](https://numba.discourse.group/t/calling-a-c-function-pointer-passed-as-argument-to-cfunc/1601/2 "2022-10-15T05:17:01Z")

</div>

I have not tried with a C compiled function, but I suspect that this would work:

```python
from numba.extending import intrinsic
from numba.core import cgutils
from numba.types import i8
from numba import types, cfunc, njit

@intrinsic
def _func_from_address(typingctx, func_type_ref, addr):
    '''Recovers a function from it's signature and address '''
    func_type = func_type_ref.instance_type
    def codegen(context, builder, sig, args):
        _, addr = args

        sfunc = cgutils.create_struct_proxy(func_type)(context, builder)

        llty = context.get_value_type(types.voidptr)
        addr_ptr = builder.inttoptr(addr,llty)

        sfunc.addr = addr_ptr
        return sfunc._getvalue()

    sig = func_type(func_type_ref, addr)
    return sig, codegen

my_c_func_type = types.FunctionType(i8(i8,i8))

@njit(i8(i8, i8, i8), cache=True)
def njit_forward(a, b, func_addr):
    f = _func_from_address(my_c_func_type, func_addr)
    return f(a,b)

@cfunc(i8(i8, i8, i8), nopython=True, cache=True)
def forward(a, b, func_addr):
    return njit_forward(a, b, func_addr)

```

It seems calling a predefined njit\_forward() inside the @cfunc implementation of forward() is necessary, because @cfunc doesn’t seem work if you call an intrinsic inside of it. I find this odd, but I imagine this is just a bug in numba. Perhaps you can fiddle with this to make something more concise.

Below is an example of how you would use this with the address of a normal jitted function. I suspect any C defined function would work also so long as you keep to numerical types. Probably also would work with pointer types, although I suspect that if everything was compiled for 64-bit addresses a C function probably wouldn’t complain if you passed it an i8 or u8 in place of a pointer. Someone more knowledgeable may have a good reason for why this is a bad idea.

```python
from numba.experimental.function_type import _get_wrapper_address

@njit(cache=True)
def foo(a,b):
    return a * b

jit_addr = _get_wrapper_address(foo, i8(i8,i8))
print(forward(4, 5, jit_addr))

```

---

<div class="post-metadata">

**Author:** ![nelson2005](https://yyz2.discourse-cdn.com/free1/user_avatar/numba.discourse.group/nelson2005/32/47_2.png) [@nelson2005](https://numba.discourse.group/u/nelson2005)\
**Post date:** [October 17, 2022, 4:18pm UTC](https://numba.discourse.group/t/calling-a-c-function-pointer-passed-as-argument-to-cfunc/1601/3 "2022-10-17T16:18:08Z")

</div>

It works! Thanks. Sorry for the late response, I was traveling over the weekend.

I actually looked at this intrinsic from CRE but had a cognitive 😉 block when thinking of applying it to an external ‘real C’ function.

cfunc not working with an the intrinsic is a key insight as well.

Much appreciated!
