我正在尝试使用SWIG包装一个C库(我没有写过,并且其接口无法更改)。这通常很简单,但是一个struct
的一个字段给我带来了麻烦。相关的struct
定义如下:
struct Token {
const char *buffer;
const char *word;
unsigned short wordlen;
// ... other fields ...
};
buffer
是普通的C字符串,应正常显示(但不可变)。 word
是问题字段。它是指向buffer
字符串内 中某处的指针,并且应理解为长度为wordlen
的字符串。我想以普通的只读字符串的形式向高级语言公开此内容,因此它们不必总是要切成薄片。
我认为处理此问题的方法是使用专门用于Token::word
的“出”字型映射,如下所示:
struct Token {
%typemap (out) const char *word {
$result = SWIG_FromCharPtrAndSize($1, ?wordlen?);
}
}
这就是我遇到的问题:如何从此类型映射访问父结构的wordlen
字段?
或者,如果有更好的方法来处理整个问题,请告诉我。
答案 0 :(得分:0)
不幸的是,SWIG似乎不支持同时映射多个结构成员。检查生成的输出,我们了解到(arg1)
指向输入结构。因此,我们必须:
word
不可变,以便不生成set
包装器。SWIG_FromCharPtrAndSize
片段-默认情况下不可用。word
映射SWIG_FromCharPtrAndSize
,指的是(arg1)->wordlen
。wordlen
,以便不进行映射(通过%ignore
对其进行映射,或者不以SWIG可见的struct
形式提供)。以下是一个完整的示例。首先,标题:
// main.h
#pragma once
struct Token {
const char *word;
unsigned short wordlen;
};
struct Token *make_token(void);
extern char *word_check;
还有SWIG模块-请注意,我们逐字使用标题,仅覆盖struct Token
的定义:
// token_mod.i
%module token_mod
%{#include "main.h"%}
%ignore Token;
%include "main.h"
%rename("%s") Token;
struct Token {
%immutable word;
%typemap (out, fragment="SWIG_FromCharPtrAndSize") const char *word {
$result = SWIG_FromCharPtrAndSize($1, (arg1)->wordlen);
}
const char *word;
%typemap (out) const char *word;
};
使用Python检查事情是否正常的演示代码:
// https://github.com/KubaO/stackoverflown/tree/master/questions/swig-pair-53915787
#include <assert.h>
#include <stdlib.h>
#include <Python.h>
#include "main.h"
struct Token *make_token(void) {
struct Token *r = malloc(sizeof(struct Token));
r->word = "1234";
r->wordlen = 2;
return r;
}
char *word_check;
#if PY_VERSION_HEX >= 0x03000000
# define SWIG_init PyInit__token_mod
PyObject*
#else
# define SWIG_init init_token_mod
void
#endif
SWIG_init(void);
int main()
{
PyImport_AppendInittab("_token_mod", SWIG_init);
Py_Initialize();
PyRun_SimpleString(
"import sys\n"
"sys.path.append('.')\n"
"import token_mod\n"
"from token_mod import *\n"
"token = make_token()\n"
"cvar.word_check = token.word\n");
assert(word_check && strcmp(word_check, "12") == 0);
Py_Finalize();
return 0;
}
最后,制作演示的CMakeLists.txt
-可以与Python 2.7或3.x一起使用。注意:要切换Python版本,必须擦除构建目录(或至少必须擦除其中的cmake缓存)。
cmake_minimum_required(VERSION 3.2)
set(Python_ADDITIONAL_VERSIONS 3.6)
project(swig-pair)
find_package(SWIG 3.0 REQUIRED)
find_package(PythonLibs 3.6 REQUIRED)
include(UseSwig)
SWIG_MODULE_INITIALIZE(${PROJECT_NAME} python)
SWIG_ADD_SOURCE_TO_MODULE(${PROJECT_NAME} swig_generated_sources "token_mod.i")
add_executable(${PROJECT_NAME} "main.c" ${swig_generated_sources})
target_include_directories(${PROJECT_NAME} PRIVATE ${PYTHON_INCLUDE_DIRS} ".")
target_link_libraries(${PROJECT_NAME} PRIVATE ${PYTHON_LIBRARIES})
答案 1 :(得分:-1)
高级语言并不关心wordlen是单词的大小。只有C可以。如果您不能更改正在痛饮的C,那么您必须将其保留为原样,并记住在用高级语言编写字符时要注意大小。 Swig和const也不喜欢彼此。 Here是否有关于const的文档