How to access dynamic arrays in struct with ctypes? - ctypes

This is my minimal example code.
import ctypes as c
import numpy as np
import subprocess
## the c code
c_code = """
#include<string.h>
#include<stdlib.h>
typedef struct My_Struct_{
int n;
float *b;
}My_Struct;
My_Struct *my_struct_new(int n) {
My_Struct *result = malloc(sizeof *result);
result->n = n;
result->b = malloc(n*sizeof result->b[0]);
memset(result->b,1.0,n*sizeof result->b[0]);
return result;
}
"""
## creating the so file
with open('temp.c', 'w') as f:
f.write(c_code)
cmmd = "gcc -std=c99 -lm -shared -o temp.so -fPIC temp.c -lm -Wall -pedantic"
print subprocess.call(cmmd, shell=True)
## importing the so file
c_foo=c.cdll.LoadLibrary("./temp.so")
n = 5
class My_Struct(c.Structure):
_fields_= [("n",c.c_int),
("b",c.POINTER(c.c_float*n))]
my_struct_new = c_foo.my_struct_new
my_struct_new.argtype = [c.c_int]
my_struct_new.restype = c.POINTER(My_Struct)
## creating the struct
p_my_struct = my_struct_new(n)
# trying to read from the struct
print p_my_struct.contents.b[0]
print np.ctypeslib.as_array(p_my_struct.contents.b, (n,1))
But instead of the expected
[[1.0, 1.0, 1.0, 1.0, 1.0]]
I get:
<__main__.c_float_Array_5 object at 0x35fe3b0>
[[]
[�#�^]
[��A��������]
[`��J�]
[t*Op]]

You passed a pointer instead of the array. It should be as_array(p_my_struct[0].b[0], (n, 1)).
Comments:
You have a typo. It should be argtypes with an s.
memset sets a char value, so each value will be c_float.from_buffer(bytearray('\1\1\1\1')) == 2.3694278276172396e-38.
If you want the values as a Python list, use p_my_struct[0].b[0][:].

Related

Calling python function fetching 'c' like struct using cython and ctypes interface in c program

I am new to cython/ctypes, and i m trying to call python function from c program using cython interface, but the data is either empty or not correct. Here is the sample program
python function
$ cat c_struct.py
#!/usr/bin/env python2.7
from ctypes import *
class Request(Structure):
_pack_ = 1
_fields_ = [
('type', c_ubyte),
('subtype', c_ubyte),
('action', c_ubyte),
('checksum', c_ushort)
]
def __repr__(self):
return "'type': {}, 'subtype': {}, 'action': {}, 'checksum': {}".format(self.type,
self.subtype, self.action, self.checksum)
req_msg = Request()
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return req_msg
else:
return "String object From Python"
cython wrapper
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const void*>data
and finally my 'C' caller
cat main.c
#include <Python.h>
#include "caller.h"
#include <stdio.h>
typedef struct {
uint8_t type;
uint8_t subtype;
uint8_t action;
uint16_t checksum;
} __attribute__ ((packed)) request_t;
int
main()
{
PyImport_AppendInittab("caller", initcaller);
Py_Initialize();
PyImport_ImportModule("caller");
const char* str = get_data_frm_python(2);
printf("Printing in C - %s\n", str);
const request_t* reqP = (request_t*)get_data_frm_python(1);
printf("Printing in C - %u, %u, %u, %u\n", reqP->type, reqP->subtype, reqP->action, reqP->checksum);
return 0;
}
and a simple makefile to build it
$ cat Makefile
target = main
cy_interface = caller
CY := cython
PYTHONINC := $(shell python-config --includes)
CFLAGS := -Wall $(PYTHONINC) -fPIC -O0 -ggdb3
LDFLAGS := $(shell python-config --ldflags)
CC=gcc
all: $(target)
%.c: %.pyx
$(CY) $+
%.o: %.c
$(CC) -fPIC $(CFLAGS) -c $+
$(target): $(cy_interface).o $(target).o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
And finally the output :(
$ ./main
Printing in Cython - String object From Python
Printing in C -
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
Printing in C - 1, 0, 0, 0
Can someone please help me in to understand on what am i doing wrong ?
Note :- If i change void* to char* atleast the string data is fetched properly, but segfaults for struct
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
print "Printing in Cython -",data
return <const char*>data
$ ./main
Printing in Cython - String object From Python
Printing in C - String object From Python
Printing in Cython - 'type': 12, 'subtype': 2, 'action': 3, 'checksum': 4660
TypeError: expected string or Unicode object, Request found
Exception TypeError: 'expected string or Unicode object, Request found' in 'caller.get_data_frm_python' ignored
Segmentation fault
<const void*>data
data is a Python object (a PyObject*). This line casts that PyObject* to void. It definitely isn't reasonable to interpret a PyObject* as either a string or a request*.
<const char*>data
This gets a pointer to the first element of a Python string (which your struct isn't). The pointer is only valid while data is still alive. Unfortunately data is a function local variable so may be almost instantly freed. It's difficult to tell exactly what's going on here but it's definitely wrong.
I don't really understand what you're trying to achieve here so I'm struggling to give advice on how to do it better. Maybe drop ctypes and use Cython with a C union?
Anyways this did the trick for me, not a perfect one but something.
$ cat caller.pyx
import sys
sys.path.insert(0, '')
from libc.stdint cimport uintptr_t
from c_struct import get_message
cdef public const void* get_data_frm_python(int typ):
data = get_message(typ)
if isinstance(data, str):
return <const char*>(data)
cdef uintptr_t ptr = <uintptr_t>(get_message(typ))
return <const void*>(ptr)
def get_message(typ):
if typ == 1:
req_msg.type = 12
req_msg.subtype = 2
req_msg.action = 3
req_msg.checksum = 0x1234
return addressof(req_msg)
else:
return "String object From Python"
$ ./main
Printing in C - String object From Python
Printing in C - 12, 2, 3, 4660

Define array of strings in Cython

Stuck on some basic Cython here - what's a canonical and efficient way to define an an array of strings in Cython? Specifically, I want to define a fixed-length constant array of char. (Please note that I would prefer not to bring in NumPy at this point.)
In C this would be:
/* cletters.c */
#include <stdio.h>
int main(void)
{
const char *headers[3] = {"to", "from", "sender"};
int i;
for (i = 0; i < 3; i++)
printf("%s\n", headers[i]);
}
Attempt in Cython:
# cython: language_level=3
# letters.pyx
cpdef main():
cdef const char *headers[3] = {"to", "from", "sender"}
print(headers)
However, this gives:
(cy) $ python3 ./setup.py build_ext --inplace --quiet
cpdef main():
cdef const char *headers[3] = {"to", "from", "sender"}
^
------------------------------------------------------------
letters.pyx:5:32: Syntax error in C variable declaration
You need two lines:
%%cython
cpdef main():
cdef const char *headers[3]
headers[:] = ['to','from','sender`]
print(headers)
Somewhat counterintuitive is than one assigns unicode-strings (Python3!) to char*. That is one of Cython's quirks. On the other hand, while initializing everything with only one value, bytes-object is needed:
%%cython
cpdef main():
cdef const char *headers[3]
headers[:] = b'init_value` ## unicode-string 'init_value' doesn't work.
print(headers)
Another alternative is the following oneliner:
%%cython
cpdef main():
cdef const char **headers=['to','from','sender`]
print(headers[0], headers[1], headers[2])
which is not exactly the same as above and leads to the following C-code:
char const **__pyx_v_headers;
...
char const *__pyx_t_1[3];
...
__pyx_t_1[0] = ((char const *)"to");
__pyx_t_1[1] = ((char const *)"from");
__pyx_t_1[2] = ((char const *)"sender");
__pyx_v_headers = __pyx_t_1;
__pyx_v_headers is of type char ** and downside is, that print(headers)no longer works out of the box.
For python3 Unicode strings, this is possible-
cdef Py_UNICODE* x[2]
x = ["hello", "worlᏪd"]
or
cdef Py_UNICODE** x
x = ["hello", "worlᏪd"]

nlohmann json version 3.2.0, runtime error

I have several json files from a game I am modding that I want to be able to process using an external application.
as far as I can tell this code is within the specifications but I get a runtime error:
terminate called after throwing an instance of 'nlohmann::detail::type_error'
what(): [json.exception.type_error.304] cannot use at() with string
this is the stripped code to reproduce the error:
#include "json.hpp"
using json = nlohmann::json;
using namespace std;
namespace ns
{
class info
{
public:
std::string id;
};
void to_json(json& j, const info& mi);
void from_json(const json& j, info& mi);
}
int main()
{
json j ="[{\"id\": \"identifier\"}]";
ns::info info = j;
return 0;
}
void ns::to_json(json& j, const ns::info& mi)
{
j = json{
{"id",mi.id},
};
}
void ns::from_json(const json& j, ns::info& mi)
{
mi.id = j.at("id").get<std::string>();
}
and here is the compiler output:
-------------- Build: Debug in jsontest (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -std=c++11 -fexceptions -g -c C:\Users\UserOne\Documents\c++\jsontest\main.cpp -o obj\Debug\main.o
mingw32-g++.exe -o bin\Debug\jsontest.exe obj\Debug\main.o
Output file is bin\Debug\jsontest.exe with size 2.82 MB
Process terminated with status 0 (0 minute(s), 3 second(s))
0 error(s), 0 warning(s) (0 minute(s), 3 second(s))
There are two problems:
json j = "..."; initializes j with a JSON string value. It doesn't try to parse the contents. For that, you need to make it a json literal instead: json j = "..."_json;
After fixing that, you have a JSON array and but you're trying to access a field of a JSON object in ns::from_json().
So, fix both of those:
json j ="{\"id\": \"identifier\"}"_json;
and it'll work.
You might also consider using raw strings to avoid escaping all the quotes:
json j = R"({"id": "identifier"})"_json;
or just using an initializer list instead of parsing a string of json:
json j = { {"id", "identifier" } };
And if your source is a string being provided as a function argument or whatever, instead of a literal known at compile time:
std::string s = R"({"id": "identifier"})";
json j = json::parse(s);

Cython - Wrapping pointer to structure from C to python

I have a C function which take pointer to struct and i want to use it in python by C-Extensions by Cython way but when i want to pass pointer to struct from python give me an error: "Cannot convert Python object to 'Foo *'"
In the below example i make object to call the C function but what passed to C function is NULL pointer.
My Trial:
hello.h
#include <stdio.h>
typedef struct
{
int x;
} Foo;
int hello(Foo* what);
hello.c
#include "hello.h"
int hello(Foo* what)
{
printf("Hello Wrapper\n");
printf("what: %p\n", what);
what->x = 5;
return what->x;
}
phello.pxd
cdef extern from "hello.h":
ctypedef struct Foo:
int x
cdef int hello(Foo* what)
phello.pyx
cimport phello
cdef class Foo_c:
cdef phello.Foo* s
def hello_fn(self):
return phello.hello(self.s)
setup.py
from distutils.core import setup, Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules=[ Extension("hellomodule",
sources=["phello.pyx", "hello.c"],
) ]
test.py
import hellomodule
print "Hello test.py"
tobject = hellomodule.Foo_c()
print "Object:", tobject
tobject.hello_fn()
So i want create "Foo" struct in "test.py" and pass it to "hello_fn()" function to call the C function "hello()" after passing this struct, so i can read or write on this structure from both sides python & C.
Can Anyone help me in this, please?
Your code does not allocate memory for phello.Foo. Allocation can be done in __cinit__ with calloc (or malloc) and deallocation in __dealloc__ with free.
cimport phello
from libc.stdlib cimport calloc, free
cdef class Foo_c:
cdef phello.Foo* s
def __cinit__(self, int n):
self.s = <phello.Foo *>calloc(1, sizeof(phello.Foo))
def __dealloc__(self):
free(<void *>self.s)
def __init__(self, int n):
self.s.x = n

Returning a tuple of tuples from c to python using ctypes

I need to return a two dimensional array of heterogenous data from my c dll to python.
I am returning a tuple of tuples for this purpose from my c dll. It is returned as PyObject *
This tuple of tuples needs to be accessed as tup[0][0] for the first row first column tup[0][1] for the first row second column ...and so on... in my python code.
I use ctypes to call the c function which returns the tuple of tuples. However , I am unable to access the returned PyObject* in the python code.
extern "C" _declspec(dllexport) PyObject *FunctionThatReturnsTuple()
{
PyObject *data = GetTupleOfTuples();
return data; //(PyObject*)pFPy_BuildValue("O", data);
}
In the python script I use the following -
libc = PyDLL("MyCDLL.dll")
x = libc.FunctionThatReturnsTuple()
if x != None :
print str( x[0][0] )
print str( x[0][1] )
However I get an error - 'int' object is not subscriptable. I think this is because x is received as pointer.
What is the right way to achieve this ?
You are not setting the return type of the "FunctionThatReturnsTuple".
In C:
#include <Python.h>
extern "C" PyObject* FunctionThatReturnsTuple()
{
PyObject* tupleOne = Py_BuildValue("(ii)",1,2);
PyObject* tupleTwo = Py_BuildValue("(ii)",3,4);
PyObject* data = Py_BuildValue("(OO)", tupleOne, tupleTwo);
return data;
}
Python:
>>> from ctypes import *
>>> libc = PyDLL("./test.dll")
>>> func = libc.FunctionThatReturnsTuple
>>> func()
-1215728020
>>> func.restype = py_object
>>> func()
((1, 2), (3, 4))