ctypes:获取c函数的实际地址

时间:2018-04-03 16:38:41

标签: python cython ctypes

这很棘手(至少对我来说:-),也许是不可行的。但我试着问你。

我有这个共享库:

#include <stdio.h>
#include <stdlib.h>

static int variable = -666;

int get_value() {
    return variable;
}

void print_pointer_to_get_value() {
    printf("pointer_to_get_value: %p\n", &get_value);
}

以这种方式编译(在Linux上):

gcc -fPIC -c -O2 shared.c && gcc -shared -o shared.so shared.o

现在我加载库并调用print_pointer_to_get_value():

>>> import ctypes
>>> so = ctypes.cdll.LoadLibrary('./shared.so')
>>> so.print_pointer_to_get_value()
pointer_to_get_value: 0x7f46e178f700

我想从ctypes获取print_pointer_to_get_value()打印的get_value函数的实际地址(整数)。 我的最终目标是将该地址移动到Cython模块并在“nogil”Cython函数中调用该函数。我需要在运行时加载.so库,因此我无法编译将其链接到库的Cython模块。

感谢1000。

1 个答案:

答案 0 :(得分:1)

这是一个令人讨厌的多步骤过程,不容易做到优雅:

一些Cython代码:

ctypedef double (*math_function_t)(double) nogil

import ctypes

def call_f(f, double x):
    cdef math_function_t cy_f_ptr = (<math_function_t*><size_t>ctypes.addressof(f))[0]

    cdef double res
    with nogil:
        res = cy_f_ptr(x)
    return res

这里我传递Cython一个Ctypes函数类型(f)并获取Cython中的地址。我认为不可能在Python中获取地址。作为如何初始化f的示例,您可以在Linux上执行以下操作:

lib = ctypes.cdll.LoadLibrary("libm.so.6")
f = lib.sin

call_f(f,0.5) # returns sin(0.5)

(使用标准库sin功能)。

Cython行cdef math_function_t cy_f_ptr = (<math_function_t*><size_t>ctypes.addressof(f))[0]可按如下方式细分:

  1. ctypes.addressof(f)获取ctypes变量f所在的地址。_这不是您追求的值_ - 它是您存储的值所在的位置
  2. 首先将其转换为size_t整数,然后转换为指向cdef函数指针类型的指针。 Cython需要两步演员。
  3. [0]取消引用您的math_function_t*获取math_function_t。这是函数指针(即你想要的值)
  4. 此答案的信息来自this newsgroup thread(我目前无法访问)