I need to use an existing library in my python application. This is a library to read a particular data file. If you are curious you can download it from here
But how do I get all the values like in the C sample code?
I'm not a C coder and I don't fully understand what is going on in lines like os->dim[dim].float64[row]
It looks like it's looping through memory.
How do I do that in python?
I hope I gave enough details. Thank you in advance.
CodePudding user response:
Here's a working example that accesses the structures mentioned with comments about corrections to the structure definitions and a port of the C code walking the structure. There is test code I used to verify the accesses were written correctly.
test.py
import ctypes as ct
SIE_OUTPUT_FLOAT64 = 1
SIE_OUTPUT_RAW = 2
class sie_Output_Raw(ct.Structure):
_fields_ = [('ptr', ct.c_void_p),
('size', ct.c_size_t), # better to use matching type for portability
('reserved_1', ct.c_int)]
class sie_Output_Dim(ct.Structure):
_fields_ = [('type', ct.c_int),
# This is a pointer type, and c_float is 32-bit so use c_double.
# Also fixed structure names to match C.
('float64', ct.POINTER(ct.c_double)),
# Use pointer to structure type since it is known instead of c_void_p.
('raw', ct.POINTER(sie_Output_Raw))]
class sie_Output_Struct(ct.Structure):
_fields_ = [('num_dims', ct.c_size_t),
('num_rows', ct.c_size_t),
('reserved_1', ct.c_size_t),
('reserved_2', ct.c_size_t),
('dim', ct.POINTER(sie_Output_Dim))] # use defined structure pointer
# CDLL/WinDLL are the same on 64-bit, but WinDLL is for 32-bit C function
# using __stdcall calling convention.
# I made a test library for demonstration. See C code below.
hllDll = ct.CDLL(r'./test')
hllDll.sie_output_get_struct.argtypes = ct.c_void_p,
# use defined structure pointer
hllDll.sie_output_get_struct.restype = ct.POINTER(sie_Output_Struct)
os = hllDll.sie_output_get_struct(None) # no need for from_address now
# port of the C code to access the structure.
# Use .contents to dereference a pointer and access the structure.
for row in range(os.contents.num_rows):
for dim in range(os.contents.num_dims):
if dim != 0:
print(', ', end='')
if os.contents.dim[dim].type == SIE_OUTPUT_FLOAT64:
print(f'{os.contents.dim[dim].float64[row]:.15g}', end='')
else:
# Equivalent to casting a C 'void*' to 'unsigned char*'
uchar_p = ct.cast(os.contents.dim[dim].raw[row].ptr, ct.POINTER(ct.c_ubyte))
size = os.contents.dim[dim].raw[row].size
if size > 16:
print(f'(raw data of size {size}.)', end='')
else:
# Slicing a pointer to a particular size creates
# creates a sized list of the array items the
# pointer points to. Result passed to bytes
# for display.
print(bytes(uchar_p[:size]), end='')
print()
test.c - Test code with a hard-coded 2x2 output.
#include <stdlib.h>
typedef double sie_float64;
typedef unsigned int sie_uint32;
typedef void sie_Output;
#define SIE_OUTPUT_NONE 0
#define SIE_OUTPUT_FLOAT64 1
#define SIE_OUTPUT_RAW 2
typedef struct _sie_Output_Raw {
void *ptr;
size_t size;
int reserved_1;
} sie_Output_Raw;
typedef struct _sie_Output_Dim {
int type;
sie_float64 *float64;
sie_Output_Raw *raw;
} sie_Output_Dim;
typedef struct _sie_Output_Struct {
size_t num_dims;
size_t num_rows;
size_t reserved_1;
size_t reserved_2;
sie_Output_Dim *dim;
} sie_Output_Struct;
__declspec(dllexport)
sie_Output_Struct* sie_output_get_struct(sie_Output* output) {
sie_Output_Struct* p = malloc(sizeof(sie_Output_Struct));
p->num_dims = 2;
p->num_rows = 2;
p->dim = malloc(2 * sizeof(sie_Output_Dim));
p->dim[0].type = SIE_OUTPUT_FLOAT64;
p->dim[0].float64 = malloc(2 * sizeof(sie_float64));
p->dim[0].raw = NULL;
p->dim[0].float64[0] = 1.5;
p->dim[0].float64[1] = 3.75;
p->dim[1].type = SIE_OUTPUT_RAW;
p->dim[1].float64 = NULL;
p->dim[1].raw = malloc(2 * sizeof(sie_Output_Raw));
p->dim[1].raw[0].ptr = "hello";
p->dim[1].raw[0].size = 5;
p->dim[1].raw[1].ptr = "there";
p->dim[1].raw[1].size = 5;
return p;
}
Output:
1.5, b'hello'
3.75, b'there'