Skip to content

Commit e2aefd3

Browse files
committed
15.12小节完成
1 parent def4fdd commit e2aefd3

File tree

1 file changed

+62
-61
lines changed

1 file changed

+62
-61
lines changed

source/c15/p12_turning_function_pointer_into_callable.rst

+62-61
Original file line numberDiff line numberDiff line change
@@ -5,82 +5,83 @@
55
----------
66
问题
77
----------
8-
You have (somehow) obtained the memory address of a compiled function, but want
9-
to turn it into a Python callable that you can use as an extension function.
8+
你已经获得了一个被编译函数的内存地址,想将它转换成一个Python可调用对象,
9+
这样的话你就可以将它作为一个扩展函数使用了。
1010

1111
|
1212
1313
----------
1414
解决方案
1515
----------
16-
The ctypes module can be used to create Python callables that wrap around arbitrary
17-
memory addresses. The following example shows how to obtain the raw, low-level ad‐
18-
dress of a C function and how to turn it back into a callable object:
16+
``ctypes`` 模块可被用来创建包装任意内存地址的Python可调用对象。
17+
下面的例子演示了怎样获取C函数的原始、底层地址,以及如何将其转换为一个可调用对象:
1918

20-
>>> import ctypes
21-
>>> lib = ctypes.cdll.LoadLibrary(None)
22-
>>> # Get the address of sin() from the C math library
23-
>>> addr = ctypes.cast(lib.sin, ctypes.c_void_p).value
24-
>>> addr
25-
140735505915760
19+
::
2620

27-
>>> # Turn the address into a callable function
28-
>>> functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double)
29-
>>> func = functype(addr)
30-
>>> func
31-
<CFunctionType object at 0x1006816d0>
21+
>>> import ctypes
22+
>>> lib = ctypes.cdll.LoadLibrary(None)
23+
>>> # Get the address of sin() from the C math library
24+
>>> addr = ctypes.cast(lib.sin, ctypes.c_void_p).value
25+
>>> addr
26+
140735505915760
3227

33-
>>> # Call the resulting function
34-
>>> func(2)
35-
0.9092974268256817
36-
>>> func(0)
37-
0.0
38-
>>>
28+
>>> # Turn the address into a callable function
29+
>>> functype = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double)
30+
>>> func = functype(addr)
31+
>>> func
32+
<CFunctionType object at 0x1006816d0>
33+
34+
>>> # Call the resulting function
35+
>>> func(2)
36+
0.9092974268256817
37+
>>> func(0)
38+
0.0
39+
>>>
3940

4041
|
4142
4243
----------
4344
讨论
4445
----------
45-
To make a callable, you must first create a CFUNCTYPE instance. The first argument to
46-
CFUNCTYPE() is the return type. Subsequent arguments are the types of the arguments.
47-
Once you have defined the function type, you wrap it around an integer memory address
48-
to create a callable object. The resulting object is used like any normal function accessed
49-
through ctypes.
50-
This recipe might look rather cryptic and low level. However, it is becoming increasingly
51-
common for programs and libraries to utilize advanced code generation techniques like
52-
just in-time compilation, as found in libraries such as LLVM.
53-
For example, here is a simple example that uses the llvmpy extension to make a small
54-
assembly function, obtain a function pointer to it, and turn it into a Python callable:
46+
要构建一个可调用对象,你首先需要创建一个 ``CFUNCTYPE`` 实例。
47+
``CFUNCTYPE()`` 的第一个参数是返回类型。
48+
接下来的参数是参数类型。一旦你定义了函数类型,你就能将它包装在一个整型内存地址上来创建一个可调用对象了。
49+
生成的对象被当做普通的可通过 ``ctypes`` 访问的函数来使用。
50+
51+
本节看上去可能有点神秘,偏底层一点。
52+
但是,但是它被广泛使用于各种高级代码生成技术比如即时编译,在LLVM函数库中可以看到。
53+
54+
例如,下面是一个使用 ``llvmpy`` 扩展的简单例子,用来构建一个小的聚集函数,获取它的函数指针,
55+
并将其转换为一个Python可调用对象。
56+
57+
::
5558

56-
>>> from llvm.core import Module, Function, Type, Builder
57-
>>> mod = Module.new('example')
58-
>>> f = Function.new(mod,Type.function(Type.double(), \
59-
[Type.double(), Type.double()], False), 'foo')
60-
>>> block = f.append_basic_block('entry')
61-
>>> builder = Builder.new(block)
62-
>>> x2 = builder.fmul(f.args[0],f.args[0])
63-
>>> y2 = builder.fmul(f.args[1],f.args[1])
64-
>>> r = builder.fadd(x2,y2)
65-
>>> builder.ret(r)
66-
<llvm.core.Instruction object at 0x10078e990>
67-
>>> from llvm.ee import ExecutionEngine
68-
>>> engine = ExecutionEngine.new(mod)
69-
>>> ptr = engine.get_pointer_to_function(f)
70-
>>> ptr
71-
4325863440
72-
>>> foo = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double, ctypes.c_double)(ptr)
59+
>>> from llvm.core import Module, Function, Type, Builder
60+
>>> mod = Module.new('example')
61+
>>> f = Function.new(mod,Type.function(Type.double(), \
62+
[Type.double(), Type.double()], False), 'foo')
63+
>>> block = f.append_basic_block('entry')
64+
>>> builder = Builder.new(block)
65+
>>> x2 = builder.fmul(f.args[0],f.args[0])
66+
>>> y2 = builder.fmul(f.args[1],f.args[1])
67+
>>> r = builder.fadd(x2,y2)
68+
>>> builder.ret(r)
69+
<llvm.core.Instruction object at 0x10078e990>
70+
>>> from llvm.ee import ExecutionEngine
71+
>>> engine = ExecutionEngine.new(mod)
72+
>>> ptr = engine.get_pointer_to_function(f)
73+
>>> ptr
74+
4325863440
75+
>>> foo = ctypes.CFUNCTYPE(ctypes.c_double, ctypes.c_double, ctypes.c_double)(ptr)
7376

74-
>>> # Call the resulting function
75-
>>> foo(2,3)
76-
13.0
77-
>>> foo(4,5)
78-
41.0
79-
>>> foo(1,2)
80-
5.0
81-
>>>
77+
>>> # Call the resulting function
78+
>>> foo(2,3)
79+
13.0
80+
>>> foo(4,5)
81+
41.0
82+
>>> foo(1,2)
83+
5.0
84+
>>>
8285

83-
It goes without saying that doing anything wrong at this level will probably cause the
84-
Python interpreter to die a horrible death. Keep in mind that you’re directly working
85-
with machine-level memory addresses and native machine code—not Python
86-
functions.
86+
并不是说在这个层面犯了任何错误就会导致Python解释器挂掉。
87+
要记得的是你是在直接跟机器级别的内存地址和本地机器码打交道,而不是Python函数。

0 commit comments

Comments
 (0)