【问题标题】:ctypes return array of strings std::vector<std::string>>ctypes 返回字符串数组 std::vector<std::string>>
【发布时间】:2022-01-01 21:27:32
【问题描述】:

我可以在转换为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)

这是我用 c 风格包装的 cpp 代码:

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;
    }

我可以在res 中看到 3 个字符串被正确复制,但是在 python 中打印时我得到:b'\xa0y\xa4P\x12\x01'

我想我正在打印指针。

【问题讨论】:

  • 试试c_lib.get_otp_data_new.restype = ctypes.POINTER(ctypes.c_char_p)
  • @Artyer 是的!谢谢!
  • 这并不是因为 sizeof(char**) == sizeof(char*) 有所不同,但从技术上讲,您的 malloc 行应该是 char** res = (char**)malloc(num * sizeof(char*));
  • 这是C++代码,不是C代码请删除C标签

标签: python c++ c string ctypes


【解决方案1】:

函数返回一个char**,你告诉Python它返回一个char*[3](3个char*指针的数组,不是指针本身),所以返回的值不是由 ctypes 正确解释。

将返回类型更改为ctypes.POINTER(ctypes.c_char_p),或者将您的程序更改为返回与char*[3] 大小相同的内容,例如std::array&lt;char*, 3&gt;struct otp_data { char *one, *two, *three; };(这将减少1 个malloc,因为您可以返回这个按价值)

【讨论】:

  • 它可以工作,但是当我完成 for 循环时出现异常进程完成并退出代码 -1073741819 (0xC0000005)
  • python.exe 中 0x00007FF839EE06BB (_ctypes.pyd) 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000000FDFDFDFD。
  • @Gilad 指针没有附加大小信息。而不是for i in otp_data: # use `i` for i in range(3): # use `otp_data[i]`
  • 如果大小不总是 3,你必须以某种方式从 dll 中返回它。您可以将其更改为返回类似struct size_and_data { int num; char** res_string }; 的结构并将restype 更改为class size_and_data(ctypes.Structure): _fields_ = [("num", ctypes.c_int), ("data", ctypes.POINTER(ctypes.c_char_p))],并使用for i in range(otp_data.num): print(otp_data.data[i])。如果大小始终为 3,您可以返回 std::array&lt;char*, 3&gt; 并将 restype 更改为 (ctypes.c_char_p * 3),它确实附加了大小。
  • C 链接函数不能返回 C++ 类 'std::array' 不能使用 std::array 它是 c++
猜你喜欢
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 2011-10-26
  • 2011-01-14
  • 1970-01-01
  • 2011-06-04
  • 2011-05-26
  • 2021-08-13
相关资源
最近更新 更多