2017-06-13 3 views
0

Ich bin ein Neuling auf Cython mit ein wenig Wissen in C und einige Python-Erfahrung. Momentan versuche ich etwas über erweiterte Typen zu lernen, aber ich kann nicht verstehen, was mit Zeigerwerten im folgenden Beispiel passiert (Code unterhalb der Erklärung).Zeigern als Attribute in erweiterten Typen Cithon

Als Übung implementiere ich einen Dummy-Solver. Das Problem wird durch zwei Zahlen "a" und "b" und die Lösung durch "s" dargestellt, wobei s = a * b.

Ich definierte zwei entsprechende C-Strukturen, problem und solution. Die Problemstruktur hat zwei int Mitglieder, 'a' und 'b'; Die Lösungsstruktur hat ein Mitglied 's. Es gibt eine Funktion, um die Problemstruktur zu initialisieren, init_problem(problem *p,int a, int b). Außerdem gibt es eine Funktion, die Zeiger auf die Strukturen nimmt und eine Lösung, solution solve(problem *p), zurückgibt. Schließlich drucken zwei andere Funktionen die Werte (void dump_problem(problem *p) und void dump_solution(solution *s)). All dies mit cdef Deklarationen.

Weiter habe ich drei Möglichkeiten, den C-Code zu Python zu exponieren: eine def Funktion do_things(int a,int b), die die C-Funktionen Wraps, und zwei cdef class, eine structs als Attribut und die andere unter Verwendung von Zeigern als Attribute Structs (Solver_s und Solver_p(), einschließlich Wrapping-Methoden, um Probleme und Lösungen zu drucken. Solver_s Klasse funktioniert wie erwartet; Bei Verwendung von Solver_p werden Zeiger jedoch nicht initialisiert und geben falsche Werte zurück (siehe test_pointer und Ausgabeabschnitte).

Ich denke, ich vermisse einen feinen Punkt über Zeiger und deren Umfang, aber ich kann nicht verstehen, was vor sich geht. Jede Hilfe, um dies zu bekommen, wird sehr geschätzt. Ich benutze Python 3.5.3 und Cython 0.25.2 in OS X 10.11.6 (El Capitan)

P.S: Das erste Mal in SO fragen, also wenn ich nicht klar bin, werde ich gerne klären!

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() 

Ausgabe

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 

Antwort

2

In Solver_p.__cinit__, p und s sind lokale Variablen, die nur für die Dauer des Anrufs existieren zu __cinit__. Die Solver_p Instanz dauert über den Aufruf hinaus, und daher sind die Zeiger während der längsten Lebensdauer ungültige Daten.

Die Lösung ist Heap-Speicher zuweisen statt:

# 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) 
     # ... 

Sie müssen vorsichtig sein, um sicherzustellen, dass der gesamte Speicher Sie zuteilen wird in geeigneter Weise befreit.


Mein Rat ist, dass, wenn Sie nicht verstehen, wie Zeiger in C korrekt verwenden, dann Sie sollten nicht sie in Cython verwendet werden.

Verwandte Themen