簡體   English   中英

使用ctypes傳遞結構指針

[英]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))]

您混合了ux 因此,您所謂的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.

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