2016-05-10 4 views
2

Ich möchte eine Liste von Zeigern von C++ zu Tcl zurückgeben. Und dann rufen Sie einige Mitgliedsfunktionen mit den Zeigern auf. SWIG kann mir dabei helfen.Swig: Wie man eine Liste von Zeigern von C++ zu Tcl zurückgibt

Allerdings SWIG geben Sie mir eine Liste von Zeiger auf Zeiger.

% getLongTime 10 
_30a8620000000000_p_p_MyData _30bc620000000000_p_p_MyData 

Ich kann die Syntax zur Dereferenzierung in SWIG nicht finden. Also muss ich für jede Klasse Dereferenzierungsfunktionen schreiben. Es ist sehr unpraktisch.

Ich schließe "std_vector.i" ein, um die Zeigerliste zurückzugeben. Hat jemand ein Beispiel, das Vektor aber ohne zweiten Zeiger verwendet? Oder irgendeine alternative Lösung ist in Ordnung!

Ich habe auch eine allgemeine dereferenzieren Funktion zu schreiben versucht, wie:

void * dereference(void ** p){ return *p; } 

Allerdings funktioniert es nicht. Tcl gibt mir Typfehler:

Ich vereinfachte meinen Code, wenn Sie mein Programm versuchen möchten. Hier mein main.cpp ist:

#include <cstdlib> 
#include <vector> 
using namespace std; 
#include "main.hh" 
#include <tcl.h> 

std::vector<MyData> MyData::AllTime;   // It seems the place of this statement matters 

std::vector<MyData*> getLongTime(int limit) { 
    vector<MyData*> longTime; 
    for(int i = 0; i <= 3; ++i) 
     if (MyData::AllTime[i].getMinute() >= limit) 
      longTime.push_back(&MyData::AllTime[i]); 
    return longTime; 
} 

MyData* derefMyData(MyData** p) {return *p;} // I have to write a dereference function for every class 

/// print command, exectue it and print resulte 
void print(Tcl_Interp *interp, const char *command) { 
    printf("%% %s\n", command); 
    Tcl_Eval(interp, command); 
    const char *msg = Tcl_GetStringResult(interp); 
    if (*msg != '\0') 
     printf("%s\n", msg); 
} 

int main(int argc, char** argv) { 
    Tcl_Interp *interp = Tcl_CreateInterp(); 
    Tcl_Eval(interp, "load ./swig.so swig"); 
    MyData::AllTime.push_back(MyData(10)); 
    MyData::AllTime.push_back(MyData(15)); 
    MyData::AllTime.push_back(MyData(9)); 

    // set the time exceeding 10 to 10 by tcl function. 
    print(interp, "set times [getLongTime 10]"); 
    print(interp, "foreach t $times { [derefMyData $t] setMinute 10}"); 

    printf("All times:"); 
    for(std::vector<MyData>::iterator i = MyData::AllTime.begin(); i != MyData::AllTime.end(); ++i) 
     printf("%d ", i->getMinute()); 
    printf("\n"); 

    Tcl_DeleteInterp(interp); 
    return 0; 
} 

Hier ist meine main.hh

#ifndef MAIN_HH 
#define MAIN_HH 

#include <cstdlib> 
#include <stdio.h> 
#include <vector> 
using namespace std; 

class MyData{ 
    int minute; 
public: 
    MyData(int minute):minute(minute){}; 
    int getMinute(){return minute;}; 
    void setMinute(int m){ minute = m; }; 
    static std::vector<MyData> AllTime; 
}; 

std::vector<MyData*> getLongTime(int limit); 
MyData* derefMyData(MyData** p); 
#endif /* MAIN_HH */ 

hier mein swig.i ist

/* swig.i */ 
%module swig 
%{ 
#include "main.hh" 
%} 
%include "std_vector.i" 
namespace std { 
    %template(myDataVector) std::vector<MyData *>; 
} 

class MyData{ 
public: 
    MyData(int minute); 
    void setMinute(int m); 
}; 

extern std::vector<MyData*> getLongTime(int limit); 
extern MyData* derefMyData(MyData** p); 

Hier ist meine Kompilierung Befehle

swig -c++ -tcl swig.i 
g++ -fpic -c main.cpp swig_wrap.cxx 
g++ -shared main.o swig_wrap.o -o swig.so ;# I don't need to compile with main.o in my original program. 
g++ main.o -o swig.out -g -I/usr/local/include -L/usr/local/lib -ltcl8.5 
setenv LD_LIBRARY_PATH /usr/local/lib:/usr/local/lib 
./swig.out 

Und hier ist der Ausgang:

% set times [getLongTime 10] 
_30a8620000000000_p_p_MyData _80bb620000000000_p_p_MyData 
% foreach t $times { [derefMyData $t] setMinute 10} 
All times:10 10 9 

By the way, das vereinfachte Programmbericht * glibc erkannt *
Ich weiß nicht, wie es zu beheben.
Glücklicherweise ist mein ursprüngliches Programm in Ordnung.
Wenn jemand weiß, wie es zu beheben ist. Lass es mich wissen, bitte.

Meine SWIG Version: 1.3.29
Meine gcc Version: 4.5.2

+0

Richtig gesprochen sollten Sie 'Tcl_FindExecutable (argv [0]);' von 'main' aufrufen, bevor Sie' Tcl_CreateInterp' ausführen, da dies die Tcl-Bibliothek initialisiert, obwohl ich nicht denke, dass das die Dinge für Sie repariert . –

Antwort

0

Ich denke, das Problem ist, dass Sie nicht einen Schluck typemap für MyData * sondern nur für MyData (oder vielleicht &MyData haben; mein C++ ist ein wenig wackelig). Das führt dazu, dass SWIG Code erzeugt, der nicht das tut, was Sie erwarten; _30a8620000000000_p_p_MyData ist ein Handle für die Zelle in dem Wert, der von der lokalen Variablen longTime kopiert wurde, und daher ist der zugeordnete Typ des Handles ein Zeiger auf Zelleninhalte, d. h. MyData **.

Sie könnte bessere Ergebnisse erzielen, wenn Sie eine const vector<MyData *> zurückgeben. Das wäre auf der Tcl-Seite sicherlich sinnvoller, wo die Werte selbst tatsächlich konstant sind. Ich weiß nicht, ob SWIG schlau genug ist, das auszunutzen. Es ist möglich, dass Sie den Typmap-Code selbst schreiben müssen (was nur sinnvoll ist, wenn Ihr realer Code viel länger ist).

Verwandte Themen