Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass const char* from python to c function

I am using ctypes in Python to open a file for writing in C++.

My C++ code:

extern "C" {
void openfile(const char *filename) {
    cout<<"File to open for writing = " <<filename<<endl;
    FILE *fp = fopen(filename,"w");
    fprintf(fp,"writing into file");
    fclose(fp);
}
}

My Python code:

>>> import ctypes
>>> lib = ctypes.cdll.LoadLibrary('/in/vrtime/mahesh/blue/rnd/software/test/test.so')
>>> outfile = "myfirstfile.txt"
>>> lib.openfile(outfile)
File to open for writing = m

I am getting the file name as m, which is the first char charater of my file.

How to pass whole string to the C side?

like image 819
Mahesh Chaurasia Avatar asked Jun 22 '16 11:06

Mahesh Chaurasia


1 Answers

In python3 (and you are definitely using python3 as on python2 your code would luckily work) strings are stored as wchar_t[] buffers, so when you pass "myfirstfile.txt" the C function sees its arg as "m\0y\0..." which is obviously a C string of lenght one. Here is the problem manifested:

In [19]: from ctypes import cdll, c_char_p

In [20]: libc = cdll.LoadLibrary("libc.so.6")

In [21]: puts = libc.puts

In [22]: puts('abc')
a

You should pass to the C function a bytes object

In [23]: puts(b'abc')
abc

You can convert str to bytes like this:

puts(my_var.encode())

To avoid further confusion you may specify the argument types of C function:

In [27]: puts.argtypes = [c_char_p]

Now the function accepts bytes (ctypes converts it to char*):

In [28]: puts(b'abc')
abc

but not str:

In [30]: puts('abc')
---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)
<ipython-input-26-aaa5b59630e2> in <module>()
----> 1 puts('abc')

ArgumentError: argument 1: <class 'TypeError'>: wrong type
like image 123
robyschek Avatar answered Nov 20 '22 16:11

robyschek