Python 扩展类型cython中作为属性的指针

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)。此外,还有一个函数可以

我是cython的新手,有点C语言知识和一些python经验。目前,我正在尝试学习扩展类型,但我无法理解以下示例中指针值会发生什么情况(解释下面的代码)

作为练习,我正在实现一个虚拟解算器。问题由两个数字“a”和“b”表示,解决方案由“s”表示,其中s=a*b

我定义了两个对应的C结构,
问题
解决方案
。问题结构有两个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中使用它们