2017-04-07 3 views
1

Ich möchte C-Module in den Python integrieren, so fiel meine Wahl auf die Schnittstelle Python.h. Alles kompiliert ohne Fehler und Warnungen, so kann ich nicht verstehen, was das Problem ist.Python/C API - Das Ergebnis wird nicht angezeigt

C Seite:

#include <python3.5m/Python.h> 
... 
#define PyInt_AsLong(x) (PyLong_AsLong((x))) 
typedef PyObject* Py; 

static Py getSumma(Py self, Py args){ 
    Py nums; 
    if (!PyArg_ParseTuple(args, "O", &nums)){ 
    return NULL; 
    } 
    size_t numsAmount = PyList_Size(args); 
    int32_t summa = 0; 

    for (size_t i = 0; i < numsAmount; i++){ 
    Py temp = PyList_GetItem(nums, i); 
    int32_t num = PyInt_AsLong(temp); 
    summa += num; 
    } 
    return Py_BuildValue("l", summa); 
} 

static PyMethodDef moduleMethods[] = { 
    {"getSumma", (PyCFunction)getSumma, METH_VARARGS, NULL}, 
    {NULL, NULL, 0, NULL} 
}; 

static PyModuleDef SummaLogic = { 
    PyModuleDef_HEAD_INIT, 
    "SummaLogic", 
    "", 
    -1, 
    moduleMethods 
}; 

PyMODINIT_FUNC PyInit_SummaLogic(void){ 
    return PyModule_Create(&SummaLogic); 
} 

setup.py:

from distutils.core import setup, Extension 

SummaLogic = Extension("SummaLogic", sources=['SummaLogic.c']) 
setup(ext_modules=[SummaLogic]) 

Python Seite:

from SummaLogic import getSumma 

if __name__ == "__main__": 
    a = [1, 2, 3] 
    b = getSumma(a) 
    print(b) 

Es scheint in Ordnung, aber wenn ich es im Terminal starten - nichts passiert, nur ohne Aktivität hängen. Was könnte ich vermissen?

Antwort

1

Es läuft auf PyList_Size und Sie nicht dort auf Fehler überprüfen.

Sie wollten es wahrscheinlich auf nums, nicht args als Argument verwenden. Allerdings verwendete man auf args und eine sehr interessante Sache passiert:

  • args ein tuple ist,
  • daher PyList_Size gescheitert und kehrte -1
  • dass -1, die zu einem unsigned size_t gegossen wurden, die wahrscheinlich in einem sehr resultierten große Zahl, wahrscheinlich 2**64-1
  • daher läuft Ihre Iteration eine "sehr lange Zeit", weil es eine ganze Weile dauert, über 2**64-1 Elemente zu iterieren (außer alle Out-of-Bound-Speicherzugriffe).

Die schnelle Lösung wäre zu verwenden:

Py_ssize_t listlength = PyList_Size(nums); /* nums instead of args */ 
if (listlength == -1) { /* check for errors */ 
    return NULL; 
} 
size_t numsAmount = (size_t)listlength /* cast to size_t only after you checked for errors */ 

Allerdings sollten Sie überprüfen, welche Fehlerbedingungen sind und Test für sie nach jedem Python-C-API-Funktionsaufruf sonst werden Sie eine Menge undefinierter bekommen Verhaltensweisen. Auch würde ich wahrscheinlich zu den definierten Rückgabetypen statt int32_t (PyInt_AsLong gibt long zurück, so dass Sie möglicherweise seltsame Casting Fehler dort auch bekommen!), size_t, ... und die typedef PyObject* Py; macht die Dinge wirklich schwierig für jemanden, der regelmäßig C-Erweiterungen schreibt.

+0

Sehr dankbar! Du hast mir viel Zeit gespart) – errfrom

+0

@errrfrom Du bist willkommen :) Ich habe tatsächlich einen Segmentierungsfehler bei der Ausführung deines Skripts bekommen, daher war es sehr einfach mit gdb zu debuggen. – MSeifert

Verwandte Themen