簡體   English   中英

如何修復“系統錯誤:<built-in function 'name'> 在 Python C 擴展中返回 NULL 而不設置錯誤”

[英]How to fix "SystemError: <built-in function 'name'> returned NULL without setting an error" in Python C Extension

工具:Python3.7(64 位),Visual C++ 10.0 我正在嘗試為 Python 創建一個 C 擴展。 首先,我正在測試一個簡單的 C 代碼,它打印一個字符串並在for循環中調用 Sleep() 函數。 但是,當我從 Python 對這個名為 gen_nums 的 C 函數進行簡單調用時,出現以下錯誤:

“系統錯誤:內置函數 gen_nums 返回 NULL 且未設置錯誤”

我認為問題出在 Sleep() 函數上; 刪除“Sleep(1000)”部分或將其放在“printf("Printed from C thread...\\n")”之前可消除此錯誤。 我查看了 Sleep() 的文檔,但找不到任何有用的東西。

代碼:

#include <Python.h>

static void gen_nums() {
    int i;
    for(i = 0; i < 10; i++) {
        printf("Printed from C thread...\n");
        Sleep(1000);
    }
}
static PyMethodDef gen_numsmethods[] = {
    {"gen_nums", gen_nums, METH_VARARGS, "This is a threading test"},
    {NULL, NULL, 0, NULL}
};
static struct PyModuleDef threadmod = {
    PyModuleDef_HEAD_INIT,
    "threadrun",
    "This is a thread test module",
    -1,
    gen_numsmethods
};

PyMODINIT_FUNC PyInit_threadrun(void) {
    return PyModule_Create(&threadmod);
}

Python調用:

threadrun.gen_nums() \\ the C module is called threadrun

結果應該是:“從 C 線程打印...”10 次,每條語句之間間隔 1 秒。

但是,程序打印該語句 10 次,然后顯示上述錯誤。

報錯的原因是這樣的:Python擴展函數必須有一定的C原型:

PyObject *func(PyObject *self, PyObject *args)

方法槽包含類型的函數指針

PyObject *(*)(Pyobject *, PyObject *)

舊的方法是將函數強制轉換為此指針類型以存儲到方法槽中。 顯式轉換將消除void (*)()PyObject *(*)(Pyobject *, PyObject *)的轉換錯誤。 轉換有效,但需要顯式轉換。 如果不存在顯式強制轉換,則 C 編譯器必須發出診斷消息

您的代碼沒有顯式轉換,因此您必須收到警告

{"gen_nums", gen_nums, METH_VARARGS, "This is a threading test"},

在任何情況下,如果有一個顯式的 cast ,該程序仍然是一個正確的程序,直到 Python 嘗試調用您的函數gen_nums() ,因為 Python 會這樣做,就好像它的原型是

PyObject *gen_nums(PyObject *, PyObject *);

現在C 標准說,雖然到目前為止一切都很好,但從現在開始程序的行為未定義的,因為C11 6.3.2.3

  1. 指向一種類型函數的指針可以轉換為指向另一種類型函數的指針,然后再返回; 結果應與原始指針相等。 如果使用轉換后的指針調用類型與引用類型不兼容的函數,則行為未定義。

你的函數返回void ,即什么都沒有,但你問“為什么只有當Sleep()在那里時它才返回NULL 。原因是“未定義的行為”。


至於如何解決這個問題,請閱讀並理解第 1 章(共 1 章)。用 C 或 C++ 擴展 Python - 那里有很多細節,但修復這個簡單函數所需的一切都在那里詳細說明。 如果您遇到問題繼續提問但參考文檔中的問題。

該函數的修復方法將其寫為

static PyObject *gen_nums(PyObject *self, PyObject *args) {
    int i;
    for(i = 0; i < 10; i++) {
        printf("Printed from C thread...\n");
        Sleep(1000);
    }
    Py_RETURN_NONE;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM