Search code examples
pythonc++posixaio

Const char* argument gives only first character (on python3)


I have created a very simple function in c++ that uses aio_write. In the arguments I get path to create a file and its size. To create new file I use int open(const char *pathname, int flags, mode_t mode).

Then I compile it to shared object using: g++ -Wall -g -Werror aio_calls.cpp -shared -o aio_calls.so -fPIC -lrt.

On python 2.7.5 everything works perfect, but on python 3.4 I only get the first character of the path. Any clue how to make it work, so it take the whole path?

Here is function code:

#include <sys/types.h>
#include <aio.h>
#include <fcntl.h>
#include <errno.h>
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <fstream>
#include "aio_calls.h"
#define DLLEXPORT extern "C"

using namespace std;

DLLEXPORT int awrite(const char *path, int size)
{
    // create the file
    cout << path << endl;
    int file = open(path, O_WRONLY | O_CREAT, 0644);

    if (file == -1)
        return errno;

    // create the buffer
    char* buffer = new char[size];

    // create the control block structure
    aiocb cb;
    memset(buffer, 'a', size);
    memset(&cb, 0, sizeof(aiocb));
    cb.aio_nbytes = size;
    cb.aio_fildes = file;
    cb.aio_offset = 0;
    cb.aio_buf = buffer;

    // write!
    if (aio_write(&cb) == -1)
    {
        close(file);
        return errno;
    }

    // wait until the request has finished
    while(aio_error(&cb) == EINPROGRESS);

    // return final status for aio request
    int ret = aio_return(&cb);
    if (ret == -1)
        return errno;

    // now clean up
    delete[] buffer;
    close(file);

    return 0;
}

As you can see I wrote cout at the beginning of my function. This is what happens on python 2:

Python 2.7.5 (default, Nov  6 2016, 00:28:07) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import cdll
>>> m=cdll.LoadLibrary('/home/administrator/Documents/aio_calls.so')
>>> m.awrite('aa.txt', 40)
aa.txt
0

And this is what happens on python 3:

Python 3.4.5 (default, May 29 2017, 15:17:55) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import cdll
>>> m=cdll.LoadLibrary('/home/administrator/Documents/aio_calls.so')
>>> m.awrite('aa.txt', 40)
a
0

Solution

  • You are right. It had to do with encoding and decoding strings in python 3.x. I googled it and this site helped me to figured it out: http://pythoncentral.io/encoding-and-decoding-strings-in-python-3-x/

    I converted string to bytes like that:

    >>> filename=bytes('aa.txt', 'utf-8') 
    

    and now my function works in python 3 as well.

    >>> m.awrite(filename, 40) 
    aa.txt 
    0 
    

    Thanks a lot @molbdnilo !