SWIG: карта «out» для поля структуры должна получить доступ к другому полю той же структуры - PullRequest
0 голосов
/ 24 декабря 2018

Я пытаюсь обернуть библиотеку C (которую я не написал, и чьи интерфейсы не могут быть изменены), используя SWIG.Это в основном просто, но есть одно поле из struct, которое доставляет мне неприятности.Соответствующее определение struct выглядит следующим образом:

struct Token {
    const char *buffer;
    const char *word;
    unsigned short wordlen;
    // ... other fields ...
};

buffer - это обычная строка C, которая должна отображаться нормально (но неизменно).word является проблемным полем.Это указатель на где-то в строке buffer, и его следует понимать как строку длиной wordlen.Я хочу представить это высокоуровневым языкам как обычную строку только для чтения, чтобы им не всегда приходилось брать фрагмент.

Я думаю способ справиться с этимэто с "out" typemap специально для Token::word, что-то вроде этого:

struct Token {
    %typemap (out) const char *word {
        $result = SWIG_FromCharPtrAndSize($1, ?wordlen?);
    }
}

, и вот где я застрял: Как получить доступ к полю wordlen родительской структурыиз этой карты типов?

Или, если есть лучший способ справиться со всей этой проблемой, пожалуйста, расскажите мне об этом.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

К сожалению, похоже, что SWIG не поддерживает сопоставление нескольких элементов структуры одновременно.Изучив сгенерированный вывод, мы узнаем, что (arg1) указывает на структуру ввода.Таким образом, мы должны:

  1. Сделать неизменным word, чтобы обертка set не создавалась.
  2. Импортировать фрагмент SWIG_FromCharPtrAndSize - он недоступенпо умолчанию.
  3. Карта word с использованием SWIG_FromCharPtrAndSize, как вы пожелали, ссылаясь на (arg1)->wordlen.
  4. Пропустить wordlen, чтобы он не отображался (либо с помощью %ignore -ingэто или не предоставлено в struct видимом для SWIG).

Ниже приведен полный пример.Во-первых, заголовок:

// 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})
0 голосов
/ 31 января 2019

Языки более высокого уровня не заботятся о том, что wordlen - это размер слова.Только C делает.Если вы не можете изменить букву C, которую вы совершаете, то вы должны оставить ее как есть и помнить, как вы пишете на более высоких языках, что у char есть размер.Также Swig и Const не любят друг друга. Здесь есть ли документация по conts

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...