You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Python ctypes将long类型vector按引用传递给C++函数的问题

解决Python ctypes传递C++ vector&的问题

你遇到的问题本质是ctypes无法直接识别C++标准库的vector类型——它是一个带有内部状态(指针、大小、容量)的复杂结构,直接用c_void_p传递相当于把一个无效的空指针塞给C++函数,必然会导致未定义行为(比如崩溃、垃圾值)。下面给你两种可行的解决方案,优先推荐第一种,兼容性和可靠性都更好。


方案一:改用C风格动态数组(推荐)

既然vector的大小不固定,我们可以在C++侧把计算结果转换成动态分配的long数组,同时返回数组的大小,再给Python提供一个释放内存的接口,避免泄漏。

修改后的C++代码(test.cpp)

#include <vector>
#include <algorithm> // 用于std::copy

extern "C" {
// 函数参数:输入字符串a、b,输出数组的指针(指针的指针),输出数组大小的指针
int pke_decrypt(char *a, char *b, long** out_array, int* out_size) {
    // 这里是你的原有逻辑,生成vector<long> v
    std::vector<long> v;
    // 示例:填充一些测试数据
    v.push_back(123);
    v.push_back(456);
    v.push_back(789);

    // 分配内存并复制数据到数组
    *out_size = static_cast<int>(v.size());
    *out_array = new long[*out_size];
    std::copy(v.begin(), v.end(), *out_array);

    return 0; // 返回状态码,0表示成功
}

// 必须提供释放内存的函数,否则会造成内存泄漏
void pke_free_long_array(long* array) {
    delete[] array;
}
}

对应的Python代码(test.py)

import ctypes

# 加载编译好的动态库
_p = ctypes.CDLL('/home/electrical/Downloads/src/libpke.so')

# 声明函数的参数类型和返回值类型
_p.pke_decrypt.argtypes = [
    ctypes.c_char_p,
    ctypes.c_char_p,
    ctypes.POINTER(ctypes.POINTER(ctypes.c_long)),
    ctypes.POINTER(ctypes.c_int)
]
_p.pke_decrypt.restype = ctypes.c_int

_p.pke_free_long_array.argtypes = [ctypes.POINTER(ctypes.c_long)]
_p.pke_free_long_array.restype = None

def decrypt(input1, input2):
    # 初始化输出参数:数组指针和大小
    out_array = ctypes.POINTER(ctypes.c_long)()
    out_size = ctypes.c_int()

    # 调用C++函数
    result_code = _p.pke_decrypt(
        input1.encode('utf-8'),
        input2.encode('utf-8'),
        ctypes.byref(out_array),
        ctypes.byref(out_size)
    )

    # 把C数组转换成Python列表
    result_list = []
    if out_size.value > 0:
        result_list = [out_array[i] for i in range(out_size.value)]

    # 释放C侧分配的内存,务必记得这一步!
    _p.pke_free_long_array(out_array)

    return result_list

方案二:直接操作C++ vector(不推荐,兼容性差)

如果一定要坚持用vector<long>&,你需要模拟vector的内存布局(不同编译器/标准库版本可能不一样,比如GCC和MSVC的vector结构就有差异),同时需要C++侧提供创建、销毁vector的接口。

修改后的C++代码

#include <vector>

extern "C" {
// 原有解密函数,接收vector引用
int pke_decrypt(char *a, char *b, std::vector<long>& v) {
    // 原有逻辑填充v
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    return 0;
}

// 创建空的vector<long>,返回指针
std::vector<long>* create_vector_long() {
    return new std::vector<long>();
}

// 销毁vector,避免内存泄漏
void destroy_vector_long(std::vector<long>* v) {
    delete v;
}
}

对应的Python代码

import ctypes

# 模拟GCC下std::vector<long>的内存结构(三个指针:起始、当前末尾、容量末尾)
class VectorLong(ctypes.Structure):
    _fields_ = [
        ("_M_start", ctypes.POINTER(ctypes.c_long)),
        ("_M_finish", ctypes.POINTER(ctypes.c_long)),
        ("_M_end_of_storage", ctypes.POINTER(ctypes.c_long))
    ]

_p = ctypes.CDLL('/home/electrical/Downloads/src/libpke.so')

# 声明各个函数的类型
_p.create_vector_long.argtypes = []
_p.create_vector_long.restype = ctypes.POINTER(VectorLong)

_p.destroy_vector_long.argtypes = [ctypes.POINTER(VectorLong)]
_p.destroy_vector_long.restype = None

_p.pke_decrypt.argtypes = [
    ctypes.c_char_p,
    ctypes.c_char_p,
    ctypes.POINTER(VectorLong)
]
_p.pke_decrypt.restype = ctypes.c_int

def decrypt(input1, input2):
    # 创建C++侧的空vector
    v_ptr = _p.create_vector_long()

    # 调用解密函数,传递vector的指针(相当于引用)
    result_code = _p.pke_decrypt(
        input1.encode('utf-8'),
        input2.encode('utf-8'),
        v_ptr
    )

    # 计算vector的大小:末尾指针减去起始指针
    vec_size = ctypes.c_long(v_ptr.contents._M_finish - v_ptr.contents._M_start).value
    # 提取所有元素到Python列表
    result_list = [v_ptr.contents._M_start[i] for i in range(vec_size)]

    # 销毁vector,释放内存
    _p.destroy_vector_long(v_ptr)

    return result_list

为什么不推荐方案二?

std::vector的内部结构是未标准化的,不同编译器(GCC/Clang/MSVC)、不同标准库版本的布局可能完全不同。比如MSVC的vector就不是三个指针,而是包含更多成员。这意味着你的代码换个环境就可能崩溃,维护成本极高。

而方案一用纯C风格的接口,所有类型都是ctypes原生支持的,兼容性拉满,也更容易调试和维护。

内容的提问来源于stack exchange,提问作者4am

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:46:35