指向 SWIG 中 C 结构的 python 指针——访问结构成员 [英] python pointer to C structure in SWIG -- accessing the struct members

查看:36
本文介绍了指向 SWIG 中 C 结构的 python 指针——访问结构成员的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 SWIG 获得一个非常基本的 Python-to-C 接口,我可以在其中将指向结构的指针传递给 C 函数并填充成员,然后我可以访问 python 中的成员.

I'm trying to get a very basic Python-to-C interface working with SWIG where I can pass a pointer to a structure to a C function and the members get populated, and I can then access the members in python.

在下面的例子中,除了当我尝试打印结构成员时,一切正常:

In the below example, everything works except when I try to print the structure members:

print swig_test.diags_mem0_get(var)

结果:

$ ./runpython.py
Traceback (most recent call last):
  File "./runpython.py", line 11, in <module>
    print swig_test.diags_mem0_get(var)
AttributeError: 'module' object has no attribute 'diags_mem0_get'

然而:

print var.mem0

结果:

$ ./runpython.py
<Swig Object of type 'uint16_t *' at 0x7f8261e15b40>swig/python detected a memory leak of type 'uint16_t *', no destructor found.

我正在关注 SWIG 3.0 文档,特别是5.5 结构和联合"部分:http://swig.org/Doc3.0/SWIGDocumentation.html#SWIG_nn31

I am following the SWIG 3.0 Documentation, specifically section "5.5 Structures and unions" here: http://swig.org/Doc3.0/SWIGDocumentation.html#SWIG_nn31

我做错了什么?

我已经把这个例子提炼成简单的骨架:

I have distilled the example down to bare bones:

swig_test.h

typedef struct diags_t {
    uint16_t mem0;
    uint16_t mem1;
} diags;

diags *malloc_diags(void);
void free_diags(diags *pdiag);

int get_diags(diags *pdiags);

swig_test.c

#include <stdlib.h>  // malloc()
#include <stdint.h>  // uint16_t
#include "swig_test.h"

int main(int argc, char **argv) {
    return 0;
}

int get_diags(diags *pdiags) {
    pdiags->mem0 = 0xdead;
    pdiags->mem1 = 0xbeef;
    return 0;
}

diags *malloc_diags(void) {
    diags *dptr = malloc(sizeof(diags));
    return dptr;
}

void free_diags(diags *pdiag) {
    if (pdiag != NULL) 
        free(pdiag);
}

swig_test.i

%module swig_test

%{
#include "swig_test.h"
%}

%include "swig_test.h"

Makefile

CXX = gcc
INCLUDES = -I./
COMPFLAGS = -c -Wall -fPIC
PYINC = /usr/include/python2.7
SWIG = /usr/bin/swig

all: swig_test _swig_test.so

swig_test: swig_test.o
    $(CXX) -Wall $^ -o $@

swig_test.o: swig_test.c
    $(CXX) $(COMPFLAGS) $(INCLUDES) $^

_swig_test.so: swig_test_wrap.o swig_test.o
    $(CXX) -shared $^ -L$(PYLIB) -lpython2.7 -o $@

swig_test_wrap.o: swig_test_wrap.c
    $(CXX) $(COMPFLAGS) $(INCLUDES) -I$(PYINC) $^

swig_test_wrap.c: swig_test.i
    $(SWIG) -python $(INCLUDES) $^

最后是简单的python示例:

And finally the simple python example:

runpython.py

#!/usr/bin/python2
import swig_test

var = swig_test.malloc_diags()

if var == 'NULL':
    print "Error, no memory left"
else:
    ret = swig_test.get_diags(var)
    if ret == 0:
        print swig_test.diags_mem0_get(var)
        print var.mem0
    swig_test.free_diags(var)

推荐答案

您正在寻找的功能来自类型映射.该文档坦率地承认乍一看,这段代码看起来有点令人困惑."以下是对我有用的方法.

The functionality you're looking for comes in typemaps. The documentation freely admits that "At first glance, this code will look a little confusing." Here's what worked for me.

本质上,typemap 是 SWIG 在需要在 Python 和 C 之间转换时交换的几行代码.它们是为 Python 到 C 单独定义的 (%typemap(in)) 和 C 到 Python (%typemap(out)).SWIG 的文档还定义了一些魔法变量:

In essence, a typemap is a few lines of code that SWIG swaps in when it needs to convert between Python and C. They're separately defined for Python to C (%typemap(in)) and C to Python (%typemap(out)). SWIG's documentation also defines a few magic variables:

$input 指的是需要转换为 C/C++ 的输入对象.

$input refers to an input object that needs to be converted to C/C++.

$result 指的是一个将由包装函数返回的对象.

$result refers to an object that is going to be returned by a wrapper function.

$1 指的是一个 C/C++ 变量,它的类型与 typemap 声明中指定的类型相同(本例中为 int).

$1 refers to a C/C++ variable that has the same type as specified in the typemap declaration (an int in this example).

对于无符号整数支持,您只需要 uint8_tuint16_tuint32_t

For unsigned integer support, you just need in and out maps for uint8_t, uint16_t, and uint32_t

以下几行提供了该功能.它们可以进入 SWIG 的 .i 文件或主标题(在它们周围使用 ifdef SWIG 保护).

The lines below provide that functionality. They can go into SWIG's .i file, or the main header (with an ifdef SWIG guard around them).

/* uintXX_t mapping: Python -> C */
%typemap(in) uint8_t {
    $1 = (uint8_t) PyInt_AsLong($input);
}
%typemap(in) uint16_t {
    $1 = (uint16_t) PyInt_AsLong($input);
}
%typemap(in) uint32_t {
    $1 = (uint32_t) PyInt_AsLong($input);
}

/* uintXX_t mapping: C -> Python */
%typemap(out) uint8_t {
    $result = PyInt_FromLong((long) $1);
}
%typemap(out) uint16_t {
    $result = PyInt_FromLong((long) $1);
}
%typemap(out) uint32_t {
    $result = PyInt_FromLong((long) $1);
}

我觉得有用的资源:

这篇关于指向 SWIG 中 C 结构的 python 指针——访问结构成员的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆