When creating ctypes variables, can one not pass values using python variables?
I have some code where I am calling a shared C library. If I pass the parameters to this C library using Method 1 (see below) things work well. But if I use Method 2, I get garbage. There are other parts to the code. But I have confirmed that when I replace Method 2 with Method 1, things work well. So something is wrong here.
If what I am doing in Method 2 is not valid, what is the alternative if I want to automate the process of running the code for different values of a given variable(s)?
Method 1 (This works well)
import ctypes as C
c_thresholds = (C.c_double * 4)()
for idx, value in enumerate(thresholds):
c_thresholds[idx] = value
goodH = Good(C.c_char('H'), C.c_double(0.5), C.c_int(100), C.c_int(20))
goodL = Good(C.c_char('L'), C.c_double(0.5), C.c_int(75), C.c_int(20))
c_parameters = Params(
var1 = C.c_int(100),
var2 = C.c_int(4),
var3 = C.c_int(5),
var4 = C.c_int(5000),
var5 = C.c_char_p("modelname"),
var6 = C.c_double(0.5),
var7 = C.c_double(90),
var8 = c_thresholds,
var9 = C.c_int(2),
H = goodH,
L = goodL
)
runsimulation(c_parameters)
Method 2 (This does not work, outputs garbage)
import ctypes as C
def create_cparams(var1, var2, var3, var4, var5, var6, var7, var8, var9):
c_thresholds = (C.c_double * 4)()
for idx, value in enumerate(var8):
c_thresholds[idx] = value
goodH = Good(C.c_char('H'), C.c_double(0.5), C.c_int(100), C.c_int(20))
goodL = Good(C.c_char('L'), C.c_double(0.5), C.c_int(75), C.c_int(20))
c_parameters = Params(
var1 = C.c_int(var1),
var2 = C.c_int(var2),
var3 = C.c_int(var3),
var4 = C.c_int(var4),
var5 = C.c_char_p(var5),
var6 = C.c_double(var6),
var7 = C.c_double(var7),
var8 = c_thresholds,
var9 = C.c_int(var9),
H = goodH,
L = goodL
)
return c_parameters
# These are python variables
var1 = 100
var2 = 4
var3 = 5
var4 = 5000
var5 = "modelname"
var6 = 0.5
var7 = 90
var8 = [1, 0.9, 0.8, 0.7]
var9 = 2
# Calling the create_cparams function defined above
c_parameters = create_cparams(var1, var2, var3, var4, var5, var6, var7, var8, var9)
runsimulation(c_parameters)
In case it is helpful the Params class is given by (does not change across the two methods):
class Params(C.Structure):
_fields_ = [
("var1", C.c_int),
("var2", C.c_int),
("var3", C.c_int),
("var4", C.c_int),
("var5", C.c_char_p ),
("var6", C.c_double),
("var7", C.c_double),
("var8", (C.c_double * 4) ),
("var9", C.c_int),
("H", Good),
("L", Good)
]
C function prototype
// runsimulation() function above calls this C function
void run_multiple_reps (struct params parameters, struct repdata *data,
int len_timepdsarr, int *timepdsarr);
// params struct on C side, which Params class duplicates
struct params
{
int var1;
int var2;
int var3;
int var4;
char *var5;
double var6;
double var7;
double var8[4];
int var9;
struct good H;
struct good L;
};
var1 = C.c_int(100)as an argument toParams(), that is value 100 is hard-coded. In Method 2, I definevar1 = 100as a regular Python variable and then in the Params arguments I do,var1 = C.c_int(var1). That is, there are no hard-coded values in the argument toParams(). I will post the C function prototype and the struct definitions. Thank you for looking into this.bytearray(c_parameters1) == bytearray(c_parameters2)for the structs from the respective methods?Params()I was using different values, which was causing the problem. That is, one of the variables had a different value and that was causing the problem. Anyhow, the good thing that came out of this is that I learnt that I don't need to explicitly do the conversion since Python does it for me. For learning that I am going to accept your answer. Also, I will look into thebytearray. I don't know what that is.bytearrayis a mutable byte string type -- not related to ctypes. It initializes using the buffer protocol, which ctypes data objects support. It's just a quick way to grab a copy of the buffer to compare it as a byte string.