Python 扩展类型cython中作为属性的指针
我是cython的新手,有点C语言知识和一些python经验。目前,我正在尝试学习扩展类型,但我无法理解以下示例中指针值会发生什么情况(解释下面的代码) 作为练习,我正在实现一个虚拟解算器。问题由两个数字“a”和“b”表示,解决方案由“s”表示,其中s=a*b 我定义了两个对应的C结构,Python 扩展类型cython中作为属性的指针,python,c,pointers,cython,Python,C,Pointers,Cython,我是cython的新手,有点C语言知识和一些python经验。目前,我正在尝试学习扩展类型,但我无法理解以下示例中指针值会发生什么情况(解释下面的代码) 作为练习,我正在实现一个虚拟解算器。问题由两个数字“a”和“b”表示,解决方案由“s”表示,其中s=a*b 我定义了两个对应的C结构,问题和解决方案。问题结构有两个int成员,‘a’和‘b’;解决方案结构有一个成员“s”。有一个函数可以初始化问题结构,init\u problem(problem*p,inta,intb)。此外,还有一个函数可以
问题
和解决方案
。问题结构有两个int成员,‘a’和‘b’;解决方案结构有一个成员“s”。有一个函数可以初始化问题结构,init\u problem(problem*p,inta,intb)
。此外,还有一个函数可以获取指向结构的指针并返回一个解决方案,solutionsolve(problem*p)
。最后,另外两个函数打印值(void dump\u problem(problem*p)
和void dump\u solution(solution*s)
)。所有这些都使用cdef
声明
接下来,我使用了三种方法向python公开C代码:一种是封装C函数的def
函数dou things(inta,intb)
,另一种是使用指向结构的指针作为属性(Solver\s
和Solver\p
),包括包装方法,打印问题和解决方案。完成预期的课堂作业;但是,当使用Solver_p时,指针似乎没有初始化,返回了不正确的值(请参阅测试指针和输出部分)
我想我遗漏了一个关于指针及其范围的要点,但我无法理解到底发生了什么。非常感谢您的帮助。我在OS X 10.11.6(El Capitan)中使用python 3.5.3和cython 0.25.2
注:第一次这么问,所以如果我不清楚,我很乐意澄清
指针.pyx
from libc.stdio cimport printf
cdef struct problem:
int a
int b
cdef struct solution:
int s
cdef void init_problem(problem *p,int a, int b):
p.a = a
p.b = b
cdef solution solve(problem *p):
cdef solution s
s.s = p.a * p.b
return(s)
cdef void dump_problem(problem *p):
printf("Problem dump: a = %d,b = %d\n",p.a,p.b)
cdef void dump_solution(solution *s):
printf("Solution dump: s= %d\n",s.s)
def do_things(int a,int b):
cdef problem p
init_problem(&p,a,b)
cdef solution s = solve(&p)
dump_problem(&p)
dump_solution(&s)
cdef class Solver_s: #Structs as attributes of Solver
cdef problem p
cdef solution s
def __cinit__(self,int a,int b):
print("\tInside Solver_s __cinit__")
init_problem(&self.p,a,b)
dump_problem(&self.p)
self.s = solve(&self.p)
dump_solution(&self.s)
print("\tGetting out of Solver_s __cinit__")
def show_problem(self):
dump_problem(&self.p)
def show_solution(self):
dump_solution(&self.s)
cdef class Solver_p: #Pointers to structs as attributes
cdef problem *pptr
cdef solution *sptr
def __cinit__(self,int a, int b):
print("\tInside Solver_p __cinit__")
cdef problem p
self.pptr = &p
cdef solution s
self.sptr = &s
init_problem(self.pptr,a,b)
dump_problem(self.pptr) #It shows right values
self.sptr[0] = solve(self.pptr)
dump_solution(self.sptr) #It shows right values
print("\tGetting out of Solver_p __cinit__")
def show_problem(self):
dump_problem(self.pptr)
def show_solution(self):
dump_solution(self.sptr)
test_pointers.py
import pyximport; pyximport.install()
import pointers
print("\tSolving as a function")
pointers.do_things(2,3)
print("\tSolving as a Extended Type, structs as attributes")
sol_s = pointers.Solver_s(4,5)
print("\t###Problem definition unsing Solver_s methods###")
sol_s.show_problem()
print("\t###Solution definition using Solver_s methods###")
sol_s.show_solution()
print("\tSolving as a Extended Type, pointers to structs as attributes")
sol_p = pointers.Solver_p(6,7)
print("\t###Problem definition unsing Solver_p methods###")
print("\t###Gives weird values###")
sol_p.show_problem()
print("\t###Solution definition using Solver_p methods###")
print("\t###Gives weird values###")
sol_p.show_solution()
输出
Solving as a function
Problem dump: a = 2,b = 3
Solution dump: s= 6
Solving as a Extended Type, structs as attributes
Inside Solver_s __cinit__
Problem dump: a = 4,b = 5
Solution dump: s= 20
Getting out of Solver_s __cinit__
###Problem definition unsing Solver_s methods###
Problem dump: a = 4,b = 5
###Solution definition using Solver_s methods###
Solution dump: s= 20
Solving as a Extended Type, pointers to structs as attributes
Inside Solver_p __cinit__
Problem dump: a = 6,b = 7
Solution dump: s= 42
Getting out of Solver_p __cinit__
###Problem definition unsing Solver_p methods###
###Gives weird values###
Problem dump: a = 1,b = 0
###Solution definition using Solver_p methods###
###Gives weird values###
Solution dump: s= 185295816
在
Solver\u p.\uuuu cinit\uuu
中,p
和s
是局部变量,仅在调用\uu cinit\uu
期间存在。Solver\p
实例持续时间超过调用时间,因此在其生命周期的大部分时间内,指针指向无效数据
解决方案是分配堆内存:
# at the top
from libc.stdlib cimport malloc, free
cdef class Solver_p:
# ....
def __cinit__(self,...):
self.pptr = <problem*>malloc(sizeof(problem))
self.sptr = <solution*>malloc(sizeof(solution))
# ...
def __dealloc__(self):
free(self.pptr)
free(self.sptr)
# ...
#在顶部
来自libc.stdlib cimport malloc,免费
cdef类求解器\u p:
# ....
定义(自身)(自我):
self.pptr=malloc(sizeof(问题))
self.sptr=malloc(sizeof(溶液))
# ...
def uu dealoc uu(自我):
免费(self.pptr)
免费(self.sptr)
# ...
您需要小心确保您分配的所有内存都已适当释放
我的建议是,如果你不知道如何在C中正确使用指针,那么你就不应该在Cython中使用它们。在
解算器中,p
,p
和s
是局部变量,它们只在调用\uu cinit>期间存在。Solver\p
实例持续时间超过调用时间,因此在其生命周期的大部分时间内,指针指向无效数据
解决方案是分配堆内存:
# at the top
from libc.stdlib cimport malloc, free
cdef class Solver_p:
# ....
def __cinit__(self,...):
self.pptr = <problem*>malloc(sizeof(problem))
self.sptr = <solution*>malloc(sizeof(solution))
# ...
def __dealloc__(self):
free(self.pptr)
free(self.sptr)
# ...
#在顶部
来自libc.stdlib cimport malloc,免费
cdef类求解器\u p:
# ....
定义(自身)(自我):
self.pptr=malloc(sizeof(问题))
self.sptr=malloc(sizeof(溶液))
# ...
def uu dealoc uu(自我):
免费(self.pptr)
免费(self.sptr)
# ...
您需要小心确保您分配的所有内存都已适当释放
我的建议是,如果您不理解如何在C中正确使用指针,那么您不应该在Cython中使用它们