15.12 将函数指针转�为�调用对象¶
问题¶
ä½ å·²ç»�获得了一个被编译函数的内å˜åœ°å�€ï¼Œæƒ³å°†å®ƒè½¬æ�¢æˆ�一个Pythonå�¯è°ƒç”¨å¯¹è±¡ï¼Œ è¿™æ ·çš„è¯�ä½ å°±å�¯ä»¥å°†å®ƒä½œä¸ºä¸€ä¸ªæ‰©å±•函数使用了。
解决方案¶
ctypes 模å�—å�¯è¢«ç”¨æ�¥åˆ›å»ºåŒ…装任æ„�内å˜åœ°å�€çš„Pythonå�¯è°ƒç”¨å¯¹è±¡ã€‚
下é�¢çš„例å�æ¼”ç¤ºäº†æ€Žæ ·èŽ·å�–C函数的原始ã€�底层地å�€ï¼Œä»¥å�Šå¦‚何将其转æ�¢ä¸ºä¸€ä¸ªå�¯è°ƒç”¨å¯¹è±¡ï¼š
>>> import ctypes
>>> lib = ctypes.cdll.LoadLibrary(None)
>>> # Get the address of sin() from the C math library
>>> addr = ctypes.cast(lib.sin, ctypes.c_void_p).value
>>> addr
140735505915760
>>> # Turn the address into a callable function
>>> functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double)
>>> func = functype(addr)
>>> func
<CFunctionType object at 0x1006816d0>
>>> # Call the resulting function
>>> func(2)
0.9092974268256817
>>> func(0)
0.0
>>>
讨论¶
è¦�构建一个å�¯è°ƒç”¨å¯¹è±¡ï¼Œä½ 首先需è¦�创建一个 CFUNCTYPE 实例。
CFUNCTYPE() 的第一个�数是返回类型。
接下æ�¥çš„å�‚数是å�‚æ•°ç±»åž‹ã€‚ä¸€æ—¦ä½ å®šä¹‰äº†å‡½æ•°ç±»åž‹ï¼Œä½ å°±èƒ½å°†å®ƒåŒ…è£…åœ¨ä¸€ä¸ªæ•´åž‹å†…å˜åœ°å�€ä¸Šæ�¥åˆ›å»ºä¸€ä¸ªå�¯è°ƒç”¨å¯¹è±¡äº†ã€‚
生�的对象被当�普通的�通过 ctypes 访问的函数�使用。
本节看上去å�¯èƒ½æœ‰ç‚¹ç¥žç§˜ï¼Œå��底层一点。 但是,但是它被广泛使用于å�„ç§�高级代ç �生æˆ�技术比如å�³æ—¶ç¼–译,在LLVM函数库ä¸å�¯ä»¥çœ‹åˆ°ã€‚
例如,下é�¢æ˜¯ä¸€ä¸ªä½¿ç”¨ llvmpy 扩展的简å�•例å�,用æ�¥æž„建一个å°�çš„è�šé›†å‡½æ•°ï¼ŒèŽ·å�–它的函数指针,
并将其转�为一个Python�调用对象。
>>> from llvm.core import Module, Function, Type, Builder
>>> mod = Module.new('example')
>>> f = Function.new(mod,Type.function(Type.double(), \
[Type.double(), Type.double()], False), 'foo')
>>> block = f.append_basic_block('entry')
>>> builder = Builder.new(block)
>>> x2 = builder.fmul(f.args[0],f.args[0])
>>> y2 = builder.fmul(f.args[1],f.args[1])
>>> r = builder.fadd(x2,y2)
>>> builder.ret(r)
<llvm.core.Instruction object at 0x10078e990>
>>> from llvm.ee import ExecutionEngine
>>> engine = ExecutionEngine.new(mod)
>>> ptr = engine.get_pointer_to_function(f)
>>> ptr
4325863440
>>> foo = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double, ctypes.c_double)(ptr)
>>> # Call the resulting function
>>> foo(2,3)
13.0
>>> foo(4,5)
41.0
>>> foo(1,2)
5.0
>>>
å¹¶ä¸�是说在这个层é�¢çŠ¯äº†ä»»ä½•é”™è¯¯å°±ä¼šå¯¼è‡´Python解释器挂掉。 è¦�è®°å¾—çš„æ˜¯ä½ æ˜¯åœ¨ç›´æŽ¥è·Ÿæœºå™¨çº§åˆ«çš„å†…å˜åœ°å�€å’Œæœ¬åœ°æœºå™¨ç �打交é�“,而ä¸�是Python函数。