Home > Blockchain >  ctypes return array of strings std::vector<std::string>>
ctypes return array of strings std::vector<std::string>>

Time:01-02

I am able to return a string after it is converted to a char*.

import ctypes
from subprocess import Popen, PIPE

# Press the green button in the gutter to run the script.

libname = "c:\temp\debug_api_lib.dll"
c_lib = ctypes.windll.LoadLibrary(libname)


class Gilad(object):
    def __init__(self, host, port):
        c_lib.menu_function_new.argtypes = [ctypes.c_char_p, ctypes.c_int]
        c_lib.menu_function_new.restype = ctypes.c_void_p

        c_lib.get_mac_address_new.argtypes = [ctypes.c_void_p]
        c_lib.get_mac_address_new.restype = ctypes.c_char_p

        c_lib.get_otp_data_new.argtypes = [ctypes.c_void_p]
        c_lib.get_otp_data_new.restype = (ctypes.c_char_p * 3)

        self.obj = c_lib.menu_function_new(host, port)

    def get_mac_address(self):
        return c_lib.get_mac_address_new(self.obj)

    def get_otp_data(self):
        return c_lib.get_otp_data_new(self.obj)


if __name__ == '__main__':
    host = "11.11.11.11".encode('utf-8')
    t = Gilad(host, 21)
    print(t.get_mac_address())
    otp_data: object = t.get_otp_data()
    for i in otp_data: //the issue is here
        print(i)

Here is my cpp code wrapped with c-style:

extern "C"
{
    __declspec(dllexport) menu_function* menu_function_new(char * host, int port)
    {
        return new menu_function(host, port);
    }

    __declspec(dllexport) char* get_mac_address_new(menu_function* menu_function)
    {
        std::string res_string = menu_function->get_mac_address();
        char* res = new char[res_string.size()];
        res_string.copy(res, res_string.size(), 0);
        res[res_string.size()] = '\0';
        return res;
    }

    __declspec(dllexport) char** get_otp_data_new(menu_function* menu_function)
    {
        int num = 3;
        std::vector<std::string> res_string = menu_function->get_otp_data();
        char** res = (char**)malloc(num * sizeof(char**));
        for (int i = 0; i < num; i  )
        {
            res[i] = (char*)malloc(res_string[i].size());
            res_string[i].copy(res[i], res_string[i].size(), 0);
            res[i][res_string[i].size()] = '\0';
        }
        return res;
    }

I can see in res the 3 strings being copied correctly, but when printing in python I get: b'\xa0y\xa4P\x12\x01'

I guess I am printing the pointers.

CodePudding user response:

The function is returning a char**, and you've told Python that it is returning a char*[3] (an array of 3 char* pointers, not a pointer itself), so the returned value isn't being interpreted properly by ctypes.

Change the return type to ctypes.POINTER(ctypes.c_char_p), or alternatively change your program to return something that has the same size as char*[3], like std::array<char*, 3> or struct otp_data { char *one, *two, *three; }; (which would be 1 less malloc since you can return this by value)

  • Related