Reputation: 39
I have the following C code which I would use from a python script.
This is just an excerpt of an auto-generated huge library which I'm not able to change, unfortunately. Here I just wanted to print the structure elements to a console to demonstrate what is going wrong.
// CFunc.h
#include <stdio.h>
typedef struct
{
int npar;
struct
{
int id;
int value;
} params[10];
} Data_t;
void Cfunc( const Data_t * d);
// CFunc.c
#include "CFunc.h"
void Cfunc( const Data_t * d)
{
int inpar = 0;
int maxnpar = 0;
printf("%d:\n", d->npar);
maxnpar = d->npar;
inpar=0;
while (maxnpar > inpar)
{
printf(" %d: %08x %08x\n", inpar, d->params[inpar].id, *(int*)&d->params[inpar].value);
inpar++;
}
}
It is compiled and linked to a share library with:
gcc -fPIC -c CFunc.c -o CFunc.o
gcc -shared -lrt -Wl,-soname,libCFunc.so.1 -o libCFunc.so CFunc.o
So I did the following implementation using ctypes:
from ctypes import *
lib = CDLL('./libCFunc.so')
class Data_2(Structure):
pass
class Data_t(Structure):
def __init__(self, list):
self.npar = len(list)
self.params = (Data_2 * self.npar)(*list)
Data_2._fields_ = [
('id', c_int),
('value', c_int),
]
Data_t._fields_ = [
('npar', c_int),
('params', POINTER(Data_2)),
]
def pyFunc(d):
lib.Cfunc.argtypes = (POINTER(Data_t),)
lib.Cfunc(byref(d))
return
So I'm initializing the structure out of a list of given tuples, in this case just 2 and calling the C-function to see its output.
paramlist = (
( 0x050000000, 0x00000000 ),
( 0x050000001, 0x447a0000 ) )
temp = Data_t(paramlist)
pyFunc(temp)
Unfortunately the output is not as expected:
2:
0: 00000000 79948ef0
1: 00007fe5 00000000
Any thoughts what I am missing ?
Upvotes: 0
Views: 2007
Reputation: 41137
[Python 3]: ctypes - A foreign function library for Python.
I restructured your code a bit.
dll.h:
#pragma once
typedef struct Data_ {
int npar;
struct
{
int id;
int value;
} params[10];
} Data;
void test(const Data *d);
dll.c:
#include "dll.h"
#include <stdio.h>
void test(const Data *d) {
int inpar = 0;
int maxnpar = 0;
printf("%d:\n", d->npar);
maxnpar = d->npar;
inpar = 0;
while (inpar < maxnpar)
{
printf(" %d: %08x %08x\n", inpar, d->params[inpar].id, *(int*)&d->params[inpar].value);
inpar++;
}
}
code.py:
#!/usr/bin/env python3
import sys
import ctypes
DLL = "./libdll.so"
class DataInner(ctypes.Structure):
_fields_ = [
("id", ctypes.c_int),
("value", ctypes.c_int),
]
DataInnerArr10 = DataInner * 10
class Data(ctypes.Structure):
_fields_ = [
("npar", ctypes.c_int),
("params", DataInnerArr10),
]
def __init__(self, data):
self.npar = len(data)
self.params = DataInnerArr10(*data)
def main():
dll_dll = ctypes.CDLL(DLL)
test_func = dll_dll.test
test_func.argtypes = [ctypes.POINTER(Data)]
param_list = (
(0x050000000, 0x00000000),
(0x050000001, 0x447a0000),
)
d = Data(param_list)
test_func(ctypes.byref(d))
print("Done.")
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
Output:
[cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054888242]> ls code.py dll.c dll.h [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054888242]> gcc -shared -fPIC -o libdll.so dll.c [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054888242]> ls code.py dll.c dll.h libdll.so [cfati@cfati-5510-0:/cygdrive/e/Work/Dev/StackOverflow/q054888242]> python3 code.py Python 3.6.4 (default, Jan 7 2018, 15:53:53) [GCC 6.4.0] on cygwin 2: 0: 50000000 00000000 1: 50000001 447a0000 Done.
Upvotes: 1