Python 到 C,使用 SWIG 设计模式处理带有输入和输出 void 指针参数的函数。

huangapple go评论75阅读模式
英文:

Python to C, SWIG design pattern for a function with input and output void pointer arguments

问题

以下是您要翻译的内容:

我有以下情景:

带有请求和响应结构的函数头:

struct request1 {
  int a1; 
  int b1;
};

struct response1 {
  int y1; 
  int z1;
};

struct request2 {
  int a2; 
  int b2;
};

struct response2 {
  int y2; 
  int z2;
};

int initialize(int type, void *request, void *response)

当类型为1时,initialize函数的实现将假定为request1和response1结构,类似地,对于类型2,将使用request2和response2结构。

问题
您能帮助我创建上述函数的SWIG接口吗?

约束条件:

  • 不会在C代码中创建内存。
  • C代码不可修改。
  • 希望Python用户不知道底层C接口的存在。

我尝试过的:
考虑到类型数量可能会不断增加,我考虑维护一个精简的SWIG接口文件。将责任留给Python用户来处理必要的类型转换/深拷贝。

此外,Python用户将知道应该随类型传递哪个结构作为请求。

我的研究让我找到了以下效率低下的接口文件解决方案:

  • 编写一个typemap以使用SWIG_ConvertPtr将传入的Python请求对象转换为SWIG指针,并将其强制转换为void指针。
  • 但是,将void指针转换为Python对象的输出似乎是不可能的,除非使用类型信息。
英文:

I have the following scenario:

Function header along with request and response structures:

struct request1 {
  int a1; 
  int b1;
};

struct response1 {
  int y1; 
  int z1;
};

struct request2 {
  int a2; 
  int b2;
};

struct response2 {
  int y2; 
  int z2;
};

int initialize(int type, void *request, void *response)

When the type is passed as 1, the implementation for initialize will assume request1 and response1 structures and similarly request2 and response2 for type 2.

Question
Could you help me with a swig interface for the above function?

Constraints:

  • No memory is created in C.
  • C code is not modifiable.
  • Preferred that the python user should be unaware of the underlying C interface.

What I tried:
Considering the number of types will be scalable, I thought of maintaining a lean swig interface file. Leave the responsibility to the python user to take care of the typecasting/deepcopy if necessary.

Also, Python user will know which structure to pass as the request along with the type.

My research led me to the following inefficient solution for the interface file:

  • Write a typemap to convert the incoming python request object to SWIG pointer using SWIG_ConvertPtr and type cast it as void pointer.
  • But for the output void pointer argument, converting the void pointer into a python object seems impossible without making use of type information.

答案1

得分: 2

以下是翻译好的部分:

test.h

不需要类型映射。 您可以创建这些结构并将它们传递给`initialize`,使用最小的SWIG接口文件 下面我添加了一个实现和一些Python代码以使用户接口更简单

struct request1 {
  int a1;
  int b1;
};

struct response1 {
  int y1;
  int z1;
};

struct request2 {
  int a2;
  int b2;
};

struct response2 {
  int y2;
  int z2;
};

int initialize(int type, void *request, void *response);

test.c

#include "test.h"

int initialize(int type, void *request, void *response) {
    if(type == 1) {
        struct request1* a = request;
        struct response1* b = response;
        b->y1 = 2 * a->a1;
        b->z1 = 2 * a->b1;
    } else {
        struct request2* a = request;
        struct response2* b = response;
        b->y2 = 3 * a->a2;
        b->z2 = 3 * a->b2;
    }
    return type;
}

test.i

%module test

%{
#include "test.h"
%}
%include "test.h"

%pythoncode %{
def initialize1(a, b):
    req = request1()
    req.a1 = a
    req.b1 = b
    res = response1()
    initialize(1, req, res)
    return res.y1, res.z1

def initialize2(a, b):
    req = request2()
    req.a2 = a
    req.b2 = b
    res = response2()
    initialize(2, req, res)
    return res.y2, res.z2
%}

演示:

>>> import test
>>> test.initialize1(2, 3)   # 使用%pythoncode助手
(4, 6)
>>> test.initialize2(2, 3)
(6, 9)
>>> rq = test.request1()    # 使用裸接口
>>> rq.a1 = 2
>>> rq.b1 = 3
>>> rs = test.response1()
>>> test.initialize(1, rq, rs)
1
>>> rs.y1
4
>>> rs.z1
6
英文:

No typemaps required. You can create the structures and pass them to initialize with the minimal SWIG interface file. Below I've added an implementation and a little Python code addition to make the interface for the user more simple:

test.h

struct request1 {
  int a1;
  int b1;
};

struct response1 {
  int y1;
  int z1;
};

struct request2 {
  int a2;
  int b2;
};

struct response2 {
  int y2;
  int z2;
};

int initialize(int type, void *request, void *response);

test.c

#include "test.h"

int initialize(int type, void *request, void *response) {
    if(type == 1) {
        struct request1* a = request;
        struct response1* b = response;
        b->y1 = 2 * a->a1;
        b->z1 = 2 * a->b1;
    } else {
        struct request2* a = request;
        struct response2* b = response;
        b->y2 = 3 * a->a2;
        b->z2 = 3 * a->b2;
    }
    return type;
}

test.i

%module test

%{
#include "test.h"
%}
%include "test.h"

%pythoncode %{
def initialize1(a, b):
    req = request1()
    req.a1 = a
    req.b1 = b
    res = response1()
    initialize(1, req, res)
    return res.y1, res.z1

def initialize2(a, b):
    req = request2()
    req.a2 = a
    req.b2 = b
    res = response2()
    initialize(2, req, res)
    return res.y2, res.z2
%}

Demo:

>>> import test
>>> test.initialize1(2, 3)   # using the %pythoncode helpers
(4, 6)
>>> test.initialize2(2, 3)
(6, 9)
>>> rq = test.request1()    # using the bare interface
>>> rq.a1 = 2
>>> rq.b1 = 3
>>> rs = test.response1()
>>> test.initialize(1, rq, rs)
1
>>> rs.y1
4
>>> rs.z1
6

huangapple
  • 本文由 发表于 2023年5月10日 18:50:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76217518.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定