【问题标题】:pointers as attributes in extended types cython指针作为扩展类型 cython 中的属性
【发布时间】:2017-11-14 21:46:33
【问题描述】:

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

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

我定义了两个对应的C结构,problemsolution。问题结构有两个 int 成员,'a' 和 'b';解决方案结构有一个成员's'。有一个函数可以初始化问题结构,init_problem(problem *p,int a, int b)。此外,还有一个函数采用指向结构的指针并返回解决方案,solution solve(problem *p)。最后,另外两个函数打印值(void dump_problem(problem *p)void dump_solution(solution *s))。所有这些都使用cdef 声明。

接下来,我使用了三种方法将 C 代码公开给 python:一个 def 函数 do_things(int a,int b) 包装了 C 函数,以及两个 cdef class,一个使用结构作为属性,另一个使用指向结构的指针作为属性(分别为Solver_sSolver_p),包括打印问题和解决方案的包装方法。 Solver_s 类按预期工作;但是,当使用 Solver_p 时,指针似乎没有被初始化,返回不正确的值(参见 test_pointers 和输出部分)。

我想我错过了关于指针及其范围的一个要点,但我无法理解发生了什么。非常感谢任何帮助。我在 OS X 10.11.6 (El Capitan) 中使用 python 3.5.3 和 cython 0.25.2

P.S:第一次问,所以如果我不清楚,我很乐意澄清!

pointers.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

【问题讨论】:

    标签: python c pointers cython


    【解决方案1】:

    Solver_p.__cinit__ps 中是局部变量,仅在调用__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)
           # ...
    

    您需要小心确保您分配的所有内存都被适当地释放。


    我的建议是,如果您不了解如何在 C 中正确使用指针,那么您不应该在 Cython 中使用它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多