How to treat output arguments like char** array in python?(如何在 python 中处理输出参数,如 char** 数组?)
问题描述
我正在尝试从 Python 脚本调用 C 方法,但在调用将 char** 数组作为参数输出的方法时遇到了问题.C层的方法如下.helper.c
文件:
I am trying to call C methods from Python script but I am facing an issue while calling the method which outputs char** array as an argument.
the method in C layer as follows. helper.c
file:
//This method takes filename as input and oNames as output
extern C int GetNames(char* iFilename, char** oNames)
{
int oNumNames, oStatus;
/*io* pIo = GetIoInstance();*/
std::vector<EString> names;
CreateIoInstance(iFilename);
oStatus = pIo->get_names(names);
oNumNames = (int)names.size();
for (int ii = 0; ii < oNumNames; ii++)
{
strcpy(oNames[ii], names[ii].c_str());
}
return 0;
}
请帮助我从 python 脚本中调用此方法.
Please help me with calling this method from python script.
from ctypes import *
dll = CDLL('D:\python\working.dll')
dll.GetNames = dll.GetNames
dll.GetNames.argtypes = (c_char_p, POINTER(c_char_p))
dll.GetStageNames.restype = c_int
filename = "in.h5"
def GetNames(filename):
ostagenames = POINTER(c_char_p)
err = dll.GetStageNames(filename, ostagenames)
return err, ostagenames.value
推荐答案
我已经简化了函数,专注于 char**
参数.在编写示例函数时,它假定内存是预先分配的,但是没有接口来指示用于输出的数组的大小或数组中的各个字符串.在这个例子中,内存是为一个 3 元素数组预先分配的,每个字符串最多 20 个字符,但实际上用户必须预先分配足够长的字符串来保存实际的返回值-生活状况.
I've simplified the function to focus on the char**
parameter. As your sample function was written it assumes memory was pre-allocated, but there is no interface to indicate the size of the array used for output or the individual strings in the array. In this example, the memory is pre-allocated for a 3-element array with a maximum of 20 characters per string, but in reality the user would have to pre-allocate enough strings with enough length to hold the return values in the real-life situation.
test.cpp:
#define API __declspec(dllexport)
#include <vector>
#include <string>
#include <cstring>
using namespace std;
//This method takes filename as input and oNames as output
extern "C" API void GetNames(char** oNames)
{
vector<string> names { "one", "two", "three" };
for (size_t i = 0; i < names.size(); ++i) {
strcpy(oNames[i], names[i].c_str());
}
}
test.py:
from ctypes import *
dll = CDLL('./test')
dll.GetNames.argtypes = POINTER(c_char_p),
dll.GetNames.restype = None
def get_names():
ARR3 = c_char_p * 3 # equivalent to char*[3] type in C
# list of 3 mutable pointers to buffers
buffers = [cast(create_string_buffer(20),c_char_p) for _ in range(3)]
names = ARR3(*buffers) # array initalized with buffers
dll.GetNames(names)
return list(names)
print(get_names())
输出:
[b'one', b'two', b'three']
如果您可以随意更改 API,那么动态分配内存以便稍后释放可以使其更加灵活.这对于 char*** 来说相当难看,但它可以工作:
If you are free to change the API, allocating memory dynamically so it can be freed later makes it more flexible. This is rather ugly with a char*** but it works:
test.cpp:
#define API __declspec(dllexport)
#include <vector>
#include <string>
#include <cstring>
using namespace std;
extern "C" {
API void GetNames(char*** oNames) {
vector<string> names { "one", "two", "three" };
auto arr = new char*[names.size() + 1];
for (size_t i = 0; i < names.size(); ++i) {
auto len = names[i].size() + 1;
arr[i] = new char[len];
strcpy_s(arr[i], len, names[i].c_str());
}
arr[names.size()] = nullptr;
*oNames = arr;
}
API void FreeNames(char** names) {
if(names) {
for(size_t i = 0; names[i]; ++i)
delete [] names[i];
delete [] names;
}
}
}
test.py:
from ctypes import *
# ctypes.c_char_p has special handling for strings,
# but hides the pointer value. Deriving a type
# from c_char_p prevents this special handling
# and allows access to the pointer, so we can later
# free it.
class PCHAR(c_char_p):
pass
dll = CDLL('./test')
dll.GetNames.argtypes = POINTER(POINTER(PCHAR)),
dll.GetNames.restype = None
dll.FreeNames.argtypes = POINTER(PCHAR),
dll.FreeNames.restype = None
def get_names():
pnames = POINTER(PCHAR)() # allocate char**
dll.GetNames(byref(pnames)) # pass char***
i = 0
names = []
while pnames[i]: # returned char* array is terminated with null
names.append(pnames[i].value) # create and save the Python byte string
i += 1
dll.FreeNames(pnames)
return names
print(get_names())
输出:
[b'one', b'two', b'three']
这篇关于如何在 python 中处理输出参数,如 char** 数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何在 python 中处理输出参数,如 char** 数组?
基础教程推荐
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 从 std::cin 读取密码 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01