![](/img/trans.png)
[英]Interacting with a c struct containing only function pointers using ctypes in python
[英]Using ctypes to pass around struct pointers
因此,到目前為止,我要做的是構建一個小的ctypes和python代碼,該代碼執行以下操作:
Python會調用C函數,並以指向空指針的指針作為參數。
C代碼創建一個類型為ReturnStruct
的結構並將其實例化,然后其數據成員將python傳入的指針設置為指向該結構。
Python多次調用另一個C函數來遞增某些值。
然后,Python檢查值。
Python調用C函數來釋放結構指針。
到目前為止,我有前三個階段的工作,但是后兩個部分卻有問題。 這是C代碼:
#include <stdio.h>
#include <stdlib.h>
//#include "runSolver.h"
#define SMB_MAX_DATA_SIZE 16
typedef struct testStruct {
double *x[11];
double *u[10];
} Test;
typedef struct returnStruct_t {
Test* vars;
} ReturnStruct;
void initalize_returnStruct(void** returnStruct){
ReturnStruct* new_returnStruct = (ReturnStruct *)malloc(sizeof(ReturnStruct));
Test* varsStruct = (Test*)malloc(sizeof(Test)*3);
int dataSize = 5;
int i;
for(i = 0; i < 3; i++){
int x;
for(x = 0; x < 11; x++)
varsStruct[i].x[x] = (double *)malloc(sizeof(double)*5);
for(x = 0; x < 10; x++)
varsStruct[i].u[x] = (double *)malloc(sizeof(double)*5);
}
new_returnStruct->vars = varsStruct;
*returnStruct = new_returnStruct;
}
void free_returnStruct(void* data){
ReturnStruct* returnStruct = data;
int i;
for(i = 0; i < 3; i++){
int x;
for(x = 1; x < 11; x++)
free(returnStruct->vars[i].x[x]);
for(x = 0; x < 10; x++)
free(returnStruct->vars[i].u[x]);
}
free(returnStruct->vars);
free(returnStruct);
}
void parallelSolver(void* data){
ReturnStruct* VarsArray = data;
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].x[0][0]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].x[10][4]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].u[0][0]);
fprintf(stderr, " This is the value: %f \n", VarsArray->vars[0].u[9][2]);
VarsArray->vars[0].x[0][0] += 20.0;
VarsArray->vars[0].x[10][4] += 203.0;
VarsArray->vars[0].u[0][0] += 202.0;
VarsArray->vars[0].u[9][2] += 202.0;
}
這是python代碼:
#!/usr/bin/python
import sys
import ctypes as ct
numOpt = 3
class vars_t(ct.Structure):
_fields_ = [("u", ct.POINTER(ct.c_double*10)),
("x", ct.POINTER(ct.c_double*11))]
class returnStruct_t(ct.Structure):
_fields_ = [("vars", vars_t*numOpt)]
runSolver = ct.CDLL('./runSolverParallel.so')
returnStructPointer = ct.POINTER(returnStruct_t)
runSolver.parallelSolver.argtypes = [ct.c_void_p()]
varsd = ct.c_void_p()
runSolver.initalize_returnStruct(ct.byref(varsd))
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
runSolver.parallelSolver(varsd)
varsdb = ct.cast(varsd, returnStruct_t)
print(varsdb.contents.vars[0].x[0][0])
runSolver.free_returnStruct(varsd)
該代碼運行良好,直到到達以下三行為止:
varsdb = ct.cast(varsd, returnStruct_t)
print(varsdb.contents.vars[0].x[0][0])
runSolver.free_returnStruct(varsd)
所有這些都會產生段錯誤。 任何有關如何使其正常工作的建議,將不勝感激!
錯誤看起來像這樣:
Starting program: /usr/bin/python UserDefinedCode.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
This is the value: 0.000000
This is the value: 0.000000
This is the value: 0.000000
This is the value: 0.000000
This is the value: 20.000000
This is the value: 203.000000
This is the value: 202.000000
This is the value: 202.000000
This is the value: 40.000000
This is the value: 406.000000
This is the value: 404.000000
This is the value: 404.000000
This is the value: 60.000000
This is the value: 609.000000
This is the value: 606.000000
This is the value: 606.000000
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff33795d4 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
(gdb) where
#0 0x00007ffff33795d4 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#1 0x00007ffff3386ea4 in ffi_call_unix64 () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#2 0x00007ffff33868c5 in ffi_call () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#3 0x00007ffff33772c2 in _ctypes_callproc () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#4 0x00007ffff3377aa2 in ?? () from /usr/lib/python2.7/lib-dynload/_ctypes.so
#5 0x00000000004d91b6 in PyObject_Call ()
#6 0x000000000054c0da in PyEval_EvalFrameEx ()
#7 0x000000000054c272 in PyEval_EvalFrameEx ()
#8 0x0000000000575d92 in PyEval_EvalCodeEx ()
#9 0x00000000004c1352 in PyRun_SimpleFileExFlags ()
#10 0x00000000004c754f in Py_Main ()
#11 0x00007ffff68cb76d in __libc_start_main (main=0x41ba10 <main>, argc=2, ubp_av=0x7fffffffe1d8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe1c8)
at libc-start.c:226
#12 0x000000000041ba41 in _start ()
您在這里至少有四個問題(實際上是五個,但一個不相關)。
(通常)導致段錯誤的行是這樣的:
varsdb = ct.cast(varsd, returnStruct_t)
這是因為您嘗試將void *
returnStruct_t
轉換為returnStruct_t
,而不是returnStruct_t *
。 由於returnStruct_t
比指針大得多,因此很有可能會在分配的頁面末尾運行。 即使它不存在段錯誤,它也會為您提供垃圾值。 等效於以下C代碼:
returnStruct_t varsdb = *(returnStruct_t *)(&varsd);
您想要的是等效於:
returnStruct_t *varsdb = (returnStruct_t *)(varsd);
換一種說法:
varsdb = ct.cast(varsd, returnStructPointer)
解決此問題后,我經常但不總是在嘗試訪問varsdb.contents.vars[0].x[0][0]
( varsdb.contents.vars[0].x[0]
本身總是安全的)。
下一個問題是您沒有正確定義結構。 這是C:
typedef struct testStruct {
double *x[11];
double *u[10];
} Test;
這是Python:
class vars_t(ct.Structure):
_fields_ = [("u", ct.POINTER(ct.c_double*10)),
("x", ct.POINTER(ct.c_double*11))]
您混合了u
和x
。 因此,您所謂的x
,被視為11個雙精度數組,實際上是u
,一個10個雙精度數組。 因此,每當您觸摸x [10]時,您都將經過數組的末尾。
修復了那個問題之后,我得到了打印出來的垃圾值。 使用clang
構建,它始終接近6.92987533417e-310
。
我認為這完全是在C代碼中。 我經常從C中的x[10][4]
和u[9][2]
行中打印出垃圾數字。同樣,使用相同的構建,我得到的是合理值的相等混合,例如26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.000000
,對於前者來說是合理的值,而對於后者則是nan
。
當我在valgrind
下運行一個簡單的C驅動程序時,每四分之一fprintf
我都會得到:
==85323== Use of uninitialised value of size 8
因此,您可能在C中的分配或初始化代碼中遇到了一個錯誤的錯誤,有時但並非總是如此。
另外,這些不是同一類型:
typedef struct returnStruct_t {
Test* vars;
} ReturnStruct;
class returnStruct_t(ct.Structure):
_fields_ = [("vars", vars_t*numOpt)]
前者是單個指針,而該指針指向Test
對象的數組。 后者是3個Test
對象。 因此,您再次嘗試讀取指向某種東西的指針,並將其作為該類型的值,在這里,您將遠遠超出分配值的末尾。
修復該問題之后,我再也不會崩潰,即使我一路上得到了垃圾打印輸出,也得到了合理的最終值,例如80.0
。 但是,當然,我仍然會獲得這些垃圾打印輸出,並且valgrind仍然在抱怨,因此顯然這仍然不是最后一個問題。
您的代碼中也有明顯的泄漏—與問題沒有直接關系,但這是一個好兆頭,表明您可能在其他地方也遇到了類似的錯誤。 您可以這樣分配x
數組:
for(x = 0; x < 11; x++)
varsStruct[i].x[x] = (double *)malloc(sizeof(double)*5);
……然后像這樣釋放它們:
for(x = 1; x < 11; x++)
free(returnStruct->vars[i].x[x]);
因此x[0]
永遠不會被釋放。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.