简体   繁体   中英

How to get value of char pointer from Python code wtih ctypes

I want to use C library on Python. Then, I want to get message ( char* ) from C library fanction.

I wrote these codes. I got result value(double* result_out) , but I didn't get message. This code shown "c_char_p(None)".

Any ideas?

I use Python 3.6, and Ubuntu Bash.

C (libdiv.so):

#define ERROR -1
#define OK     0

int div (double x, double y, char *msg, double *result_out) {
    static char *err_msg = "0 div error"; 
    if(y == 0) {
        msg = err_msg;
        return ERROR;
    }
    *result_out = x/y;
    return OK;
}

Python:

from ctypes import *

lib = cdll.Loadlibrary('libdiv.so')
errmsg = c_char_p()
result = c_double(0)
rtn = lib.div(10, 0, errmsg, byref(result))

if rtn < 0:
    print (errmsg)       # None    
else :
    print (result.value) # OK.

The primary problem here is that your C is busted. Assigning a value to the msg argument doesn't do anything visible on the caller's end (just like if you'd tried to assign to an argument in a Python function).

If you want to actually make the error message string available to the caller of div , you need to take a char** , not a char* , and assign to *msg . On the Python end, you'd pass something like byref(errmsg) .

Aside from that, you need to set the argtypes and restype on lib.div , or Python won't know how to pass arguments correctly.

To return a value as an output parameter, you need to pass a pointer to the value type returned. Just like you used double* to receive a double, you need a char** to receive a char* :

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

#define OK     0
#define ERROR -1

API int div(double x, double y, char** ppMsg, double* pOut)
{
    static char* err_msg = "0 div error";
    if(y == 0)
    {
        *ppMsg = err_msg;
        return ERROR;
    }
    *pOut = x / y;
    return OK;
}

In Python, you'll also need to declare the argument types, or Python will marshal the values to C as c_int by default, which will break double and may break char* depending on the pointer implementation of your OS:

from ctypes import *

lib = CDLL('test')
lib.div.argtypes = c_double,c_double,POINTER(c_char_p),POINTER(c_double)
lib.div.restype  = c_int

errmsg = c_char_p()
result = c_double()
rtn = lib.div(10, 0, byref(errmsg), byref(result))

if rtn < 0:
    print(errmsg.value)
else:
    print(result.value)

Output:

b'0 div error'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM