[Python] 使用 ctypes 要小心指定函式的參數型別
專案程式有用 python 的 ctypes 呼叫一個用 C 寫的 shared library,
今天遇到一個奇怪的問題,用 python 從 PostgreSQL 讀進來的一個 BIGSERIAL 值,
傳到 shared library 之後值就錯掉了…
PostgreSQL 的 BIGSERIAL 理論上要可以支援 1~9223372036854775807,
但是我們傳進一個小於 9223372036854775807 的值,值卻會亂掉…
舉例來說,下面是一個用 C 寫的 shared library,
foo() 這個函式可以接受三個參數,注意最後一個是 long long 的型態:
#include <stdio.h> extern "C" { void foo(unsigned int a, const char* b, long long c); }; void foo(unsigned int a, const char* b, long long c) { printf("a=%d, b=%s, c=%lld\n", a, b, c); }
而在 python 這邊,用 ctypes 載入 shared library 之後,用 argtypes 指定函式的參數型態,
但因為程式修改時有些錯誤,因此最後對應到參數 c 的型態沒有被修正成 ctypes.c_longlong:
import ctypes dll = ctypes.CDLL("libtest.so") # Get import function of SetDebugFunction dll.foo.argtypes = [ctypes.c_uint, ctypes.c_char_p, ctypes.c_int] dll.foo.restype = None dll.foo(123, "456", 789012345678)
因為這個失誤,導致函式雖然可以呼叫,但值是不正確的:
testuser@localhost ~ $ python testlib.py a=123, b=456, c=-1261636786
修正方法就是要確保 python 這個定義的函式參數型別,和 shared library 的函式參數型別都是一致的:
dll.foo.argtypes = [ctypes.c_uint, ctypes.c_char_p, ctypes.c_longlong]
修正之後,程式執行就沒有問題囉:
testuser@localhost ~ $ python testlib.py a=123, b=456, c=789012345678
參考資料:python ctypes
(本頁面已被瀏覽過 2,009 次)
2 thoughts on “[Python] 使用 ctypes 要小心指定函式的參數型別”
不好意思
請問 restype 是做什麼的??
就是指定這個函式的回傳值型態。
像是例子中的這個 C 函式:
void foo(unsigned int a, const char* b, long long c);
它的回傳值是 void,對應到 python 就是 None
dll.foo.restype = None