Templates in C möglich machen?
-
Was ist eigentlich der Hintergrund, dass du dich genötigt siehst fremden Code in C zu verwenden und zu ändern, nur damit du deinen eigenen C++-Code einfügen kannst?
Naja: Wenn ich meinen Code nutzbar machen will in CODE_OTHER geht das doch nicht anders. Ich will dass die algorithmen innerhalb CODE_OTHER auf CODE_MY zurückgreifen können. Wäre das so nicht der richtige weg?
@ Pumuckl:
Herzlichen Dank für das Beispiel. Mir wird vieles klarer. Ich versuche gerade das Beispiel zu kompilieren. Sehe ich das richtig dass ich aus dem C++ code erstmal eine library (static) erstellen muss. Ich mache das unter linux im moment so:ar rcs libmaincpp.a MyB.o MyC.oAnschließend gehe ich zu dem "neuen" C-code der dne c++ code nutzen. Sehe ich das richtig dass ich hier dann gegn die library linken muss:
gcc -o mainnew mainnew.c -L lmaincpp.aoder so ählnich?
Aufgrund der undefined refeerences vermute ich dass beim linken etwas faul wird...
-
Ich bin weiterhin verwirrt wie ich eine LIbrary erstellen soll die nur aus headern besteht !? Bei der benutzung von templates kann ich doch nur header erstellen...ich habe keine *.cpp file für MyC.h ?
-
Testo schrieb:
Ich bin weiterhin verwirrt wie ich eine LIbrary erstellen soll die nur aus headern besteht !? Bei der benutzung von templates kann ich doch nur header erstellen...ich habe keine *.cpp file für MyC.h ?
Dann hast du pumuckl & Co nicht verstanden.
Du musst für deinen C++ Code einen Wrapper schreiben, und dort musst du die Templates auch auf konkrete Typen festlegen. Anders geht es nicht.
-
Jetzt versteh ich nur noch Bahnhof.
Ich dachte den wrapper hat pumuckl mir schon geschrieben. Da sind doch die cpp wrapper oder nicht? MIr istklar dass ich da in den leeren wappern noch was füllen muss...sehe ihc das falsch?
-
Testo schrieb:
Jetzt versteh ich nur noch Bahnhof.
Ich dachte den wrapper hat pumuckl mir schon geschrieben. Da sind doch die cpp wrapper oder nicht? MIr istklar dass ich da in den leeren wappern noch was füllen muss...sehe ihc das falsch?Also ich sehe in seinem Wrapper durchaus cpp-Dateien. Und eben diese bilden deine Schnittstelle für C (Sprich: Sind Teil der C++ Bibliothek, und nicht etwa des C-Programmes).
-
Es tut mir echt leid aber ich schaffe es aus eigener Kraft nicht.
Ich beschreibe es nochmal was ich tue:Ich habe C++ code:
// MyC.h#ifndef MyC_ #define MyC_ #include <iostream> template<class T> class MyC { public: MyC<T>() { data = new T[10]; memset(data, 0, 10*sizeof(T)); } ~MyC<T>() { delete [] data; } void print(MyC<int>* mtx); T* data; }; template <> void MyC<int>::print(MyC<int>* mtx) { // Hier z.B. mtx ausgeben oder andere // Dinge mit mtx tun... int a; for (int i = 0; i <10; i++) std::cout << mtx->data[i] << std::endl; } #endif#ifndef MyB_ #define MyB_ #include "MyC.h" template<class T> class MyB { public: MyB<T>() { mydata = new T[10]; } // do something with mtx void Algorithm(MyC<T>*& mtx) { for (int i= 0; i < 10; i++) mtx->data[i] = i; mtx->print(mtx); memcpy(mtx->data,mydata,10*sizeof(T)); } T* mydata; }; #endifUnd so wie ich es vertanden habe brauche ich für diese Klassen jetz wrapper:
Also cpp-wrapper:
// myb_wrapper.h#ifdef __cplusplus extern "C" { #endif typedef struct WrapMyB_int_ { void* ptr; } WrapMyB_int; WrapMyB_int myb_int_create(void); void myb_int_algorithm(WrapMyB_int this_, WrapMyC_int arg); void myb_int_delete(WrapMyB_int this_); #ifdef __cplusplus } /*end extern "C"*/ #endifdie myb_wrapper.cpp
#include "myb_wrapper.h" #include "myc_wrapper.h" #include "C++/MyB.h" //MyB<T> WrapMyB_int myb_int_create(void) { WrapMyB_int tmp; tmp.ptr = new MyB<int>(); return tmp; } void myb_int_algorithm(WrapMyB_int this_, WrapMyC_int arg) { MyB<int>* mb = static_cast<MyB<int>*> (this_.ptr); //mb->Algorithm(arg); } void myb_int_delete(WrapMyB_int this_) { MyB<int>* mb = static_cast<MyB<int>*> (this_.ptr); delete mb; this_.ptr = NULL; }und analog:
//myc_wrapper.h#ifdef __cplusplus extern "C" { #endif typedef struct WrapMyC_int_ { void* ptr; } WrapMyC_int; WrapMyC_int myc_int_create(void); // WrapMyC_int myc_int_create_1(int* data); // void myc_int_writetobuffer(WrapMyC_int this_, int* buffer); void myc_int_delete(WrapMyC_int this_); #ifdef __cplusplus } /*end extern "C"*/ #endifund die cpp myc_wrapper.cpp
#include "myc_wrapper.h" #include "C++/MyC.h" //MyC<T> WrapMyC_int myc_int_create(void) { WrapMyC_int tmp; tmp.ptr = new MyC<int>(); return tmp; } // WrapMyC_int myc_int_create_1(int* data) // { // // } // void myc_int_writetobuffer(WrapMyC_int this_, int* buffer) // { // /* ... */ // } void myc_int_delete(WrapMyC_int this_) { MyC<int>* mc = static_cast<MyC<int>*> (this_.ptr); delete mc; this_.ptr = NULL; }Jetzt kompiliere ich folgendes:
g++ -c myb_wrapper.cpp g++ -c myc_wrapper.cppund erhalte objekte davon.
Ich baue mir eine statische library überar -r libmyLib.a myc_wrapper.o myb_wrapper.oJetzt habe cih meinen C-Code:
//mainnew.c//main.c #include "myc_wrapper.h" #include "myb_wrapper.h" #include "stdlib.h" int main() { int i; int* data = calloc(10, sizeof(int)); for (i = 10; i > 0; i--) data[10-i] = i; /*...*/ //MyC<int> * mtx = new MyC<int>(); WrapMyC_int mtx = myc_int_create(); //konstruktor //MyB<int>().Algorithm(mtx); WrapMyB_int tmp = myb_int_create(); //konstruktor //myb_int_algorithm(tmp, mtx); //methode myc_int_delete(mtx); //destruktor myb_int_delete(tmp); //destruktor /*...*/ // //MyC<int>* mtx = convert_data_to_MyC(data); // WrapMyC_int mtx2 = myc_int_create_1(data); //anderer konstruktor // // //MyB<int>().Algorithm(mtx); // WrapMyB_int tmp2 = myb_int_create(); //konstruktor // myb_int_algorithm(tmp2, mtx2); //methode // myc_int_writetobuffer(mtx2, data); // // myc_int_delete(mtx2); //destruktor // myb_int_delete(tmp2); //destruktor // // for (i = 0; i < 10; i++) // printf("data[%d] = %d\n", i, data[i]); free(data); }Den ich kompiliere über:
gcc -o mainnew mainnew.c -L lmyLib.aIch erhalte aber folgende Probleme:
/tmp/cc0e4n2e.o: In function `main': mainnew.c:(.text+0x57): undefined reference to `myc_int_create' mainnew.c:(.text+0x6b): undefined reference to `myb_int_create' mainnew.c:(.text+0x7f): undefined reference to `myc_int_delete' mainnew.c:(.text+0x8a): undefined reference to `myb_int_delete' collect2: ld gab 1 als Ende-Status zurückWas mache ich falsch?
-
Du mußt ein kleines 'l' für das Linken verwenden (das große 'L' bezeichnet den Pfad zu den Linkerdateien):
gcc -o mainnew mainnew.c -lmyLib
-
fällt dir was auf?
ar -r libmyLib.a myc_wrapper.o myb_wrapper.ogcc -o mainnew mainnew.c -L lmyLib.aWie heißt die Lib denn nu wirklich?
-
und dort musst du die Templates auch auf konkrete Typen festlegen.
was irgendwo die Templates sinnlos macht... Aber scheint mir auch die einzige vernünftige Lösung zu sein. Wobei mir der Sinn des Ganzen immernoch nicht klar ist. Sollen die "User" halt nen C++-Compiler benutzen. Man kann nunmal nicht alles haben.
-
Die Lib heißt: libmyLib.a
Aber man kompiliert doch in gcc über -L lmylib.a.
Es klappt für keine der Varianten:
1 Variante:
gcc -o mainnew mainnew.c -lmyLib warning: no newline at end of file /usr/bin/ld: cannot find -lmyLib.a collect2: ld gab 1 als Ende-Status zurück2 Variante
gcc -o mainnew mainnew.c libmyLib.a mainnew.c:42:2: warning: no newline at end of file libmyLib.a(myb_wrapper.o): In function `MyC<int>::print(MyC<int>*)': myb_wrapper.cpp:(.text+0xf6): multiple definition of `MyC<int>::print(MyC<int>*)' libmyLib.a(myc_wrapper.o):myc_wrapper.cpp:(.text+0x100): first defined here libmyLib.a(myc_wrapper.o): In function `__static_initialization_and_destruction_0(int, int)': myc_wrapper.cpp:(.text+0x23): undefined reference to `std::ios_base::Init::Init()' libmyLib.a(myc_wrapper.o): In function `__tcf_0': myc_wrapper.cpp:(.text+0x6c): undefined reference to `std::ios_base::Init::~Init()' libmyLib.a(myc_wrapper.o): In function `myc_int_delete': myc_wrapper.cpp:(.text+0x9c): undefined reference to `operator delete(void*)' libmyLib.a(myc_wrapper.o): In function `myc_int_create': myc_wrapper.cpp:(.text+0xb9): undefined reference to `operator new(unsigned int)' myc_wrapper.cpp:(.text+0xe2): undefined reference to `operator delete(void*)' libmyLib.a(myc_wrapper.o): In function `MyC<int>::print(MyC<int>*)': myc_wrapper.cpp:(.text+0x126): undefined reference to `std::cout' myc_wrapper.cpp:(.text+0x12b): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(int)' myc_wrapper.cpp:(.text+0x133): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)' myc_wrapper.cpp:(.text+0x13b): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))' libmyLib.a(myc_wrapper.o): In function `MyC<int>::~MyC()': myc_wrapper.cpp:(.text._ZN3MyCIiED1Ev[MyC<int>::~MyC()]+0x18): undefined reference to `operator delete[](void*)' libmyLib.a(myc_wrapper.o): In function `MyC<int>::MyC()': myc_wrapper.cpp:(.text._ZN3MyCIiEC1Ev[MyC<int>::MyC()]+0xf): undefined reference to `operator new[](unsigned int)' libmyLib.a(myc_wrapper.o):(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' libmyLib.a(myb_wrapper.o): In function `__static_initialization_and_destruction_0(int, int)': myb_wrapper.cpp:(.text+0x31): undefined reference to `std::ios_base::Init::Init()' libmyLib.a(myb_wrapper.o): In function `__tcf_0': myb_wrapper.cpp:(.text+0x7a): undefined reference to `std::ios_base::Init::~Init()' libmyLib.a(myb_wrapper.o): In function `myb_int_delete': myb_wrapper.cpp:(.text+0x93): undefined reference to `operator delete(void*)' libmyLib.a(myb_wrapper.o): In function `myb_int_create': myb_wrapper.cpp:(.text+0xaf): undefined reference to `operator new(unsigned int)' myb_wrapper.cpp:(.text+0xd8): undefined reference to `operator delete(void*)' libmyLib.a(myb_wrapper.o): In function `MyC<int>::print(MyC<int>*)': myb_wrapper.cpp:(.text+0x11c): undefined reference to `std::cout' myb_wrapper.cpp:(.text+0x121): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(int)' myb_wrapper.cpp:(.text+0x129): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)' myb_wrapper.cpp:(.text+0x131): undefined reference to `std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))' libmyLib.a(myb_wrapper.o): In function `MyB<int>::MyB()': myb_wrapper.cpp:(.text._ZN3MyBIiEC1Ev[MyB<int>::MyB()]+0xe): undefined reference to `operator new[](unsigned int)' libmyLib.a(myb_wrapper.o):(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' collect2: ld gab 1 als Ende-Status zurück3 Variante
gcc -o mainnew mainnew.c -libmyLib.a mainnew.c:42:2: warning: no newline at end of file /usr/bin/ld: cannot find -libmyLib.a collect2: ld gab 1 als Ende-Status zurück4 Variante
gcc -o mainnew mainnew.c -L libmyLib.a mainnew.c:42:2: warning: no newline at end of file /tmp/cc2XoFP3.o: In function `main': mainnew.c:(.text+0x57): undefined reference to `myc_int_create' mainnew.c:(.text+0x6b): undefined reference to `myb_int_create' mainnew.c:(.text+0x7f): undefined reference to `myc_int_delete' mainnew.c:(.text+0x8a): undefined reference to `myb_int_delete' collect2: ld gab 1 als Ende-Status zurück
-
hmm....wo liegt mein fehler
?
-
1. Um eine statische Bibliothek hinzuzulinken, gibst Du entweder die Bibliothek selbst als Objekt (d.h. ohne zusätzliche Parameter) an (Variante 2) oder aber Du gibst das Verzeichnis der Bibliothek mit -L und die Bibliothek ohne lib und .a mit -l an (Variante 1 plus z.B. "-L.")
Also Variante 2
gcc -o mainnew mainnew.c libmyLib.aOder Variante 1 (korrigiert)
gcc -o mainnew mainnew.c -L. -lmyLib2. Die Undefined References kommen daher, dass der gcc (C-Compiler bzw. Linker) kein Bewusstsein über die C++-Standardbibliothek hat. Das heißt, Du musst diese zusätzlich mittels -lstdc++ angeben.
3. Die Multiple Definition von MyC<int>::print kommt nun daher, dass vollständige Spezialisierungen von Templates vollständige Definitionen sind, und diese sind per se nicht inline. Sprich, in jeder Übersetzungseinheit, in der Du MyC.h inkludierst, hast Du eine vollständige Definition von MyC<int>::print. Um das zu umgehen, kannst Du die Definition von MyC<int>::print mit inline kennzeichnen, oder die Definition in myb_wrapper.cpp auslagern und in MyC.h lediglich eine Deklaration stehenlassen.
-
Vielen Dank für das weitere Helfen. Verstehe....sehr interessant.
ich kompiliere nun über:
gcc -o mainnew mainnew.c libmyLib.a -lstdc++und meine MyC.h sieht so aus:
#ifndef MyC_ #define MyC_ #include <iostream> template<class T> class MyC { public: MyC<T>() { data = new T[10]; memset(data, 0, 10*sizeof(T)); } ~MyC<T>() { delete [] data; } void print(MyC<int>* mtx); T* data; }; inline template <> void MyC<int>::print(MyC<int>* mtx) { // Hier z.B. mtx ausgeben oder andere // Dinge mit mtx tun... for (int i = 0; i <10; i++) std::cout << mtx->data[i] << std::endl; } #endifaber selbst das inline wie Du vorgeschlagen hast löst das Problem
nicht:gcc -o mainnew mainnew.c libmyLib.a -lstdc++ libmyLib.a(myb_wrapper.o): In function `MyC<int>::print(MyC<int>*)': myb_wrapper.cpp:(.text+0xf6): multiple definition of `MyC<int>::print(MyC<int>*)' libmyLib.a(myc_wrapper.o):myc_wrapper.cpp:(.text+0x100): first defined here collect2: ld gab 1 als Ende-Status zurückHabe ich mit dem inline was falsch gemacht?
-
Ah, ich hatte natürlich die kompilation von my*_wrapper.cpp vegessen. Jetzt geht es. danke.
-
Ich bin sehr dankbar dass ich schon mal den ersten Teil kompilieren kann. Mir fehlt jetzt nur noch mein Ausgangssinn dass ich auch data verändern kann.
mir ist nicht klar warum die kompilation so fehlschlägt:g++ -c myb_wrapper.cpp myb_wrapper.cpp: In function »void myb_int_algorithm(WrapMyB_int, WrapMyC_int)«: myb_wrapper.cpp:14: Fehler: ungültiges static_cast vom Typ »WrapMyC_int« in den Typ »MyC<int>*«Mein Code sieht so aus:
//mainnew.c #include "myc_wrapper.h" #include "myb_wrapper.h" #include "stdlib.h" int main() { int i; int* data = calloc(10, sizeof(int)); for (i = 10; i > 0; i--) data[10-i] = i; /*...*/ //MyC<int> * mtx = new MyC<int>(); WrapMyC_int mtx = myc_int_create(); //constructor //MyB<int>().Algorithm(mtx); WrapMyB_int tmp = myb_int_create(); //constructor //myb_int_algorithm(tmp, mtx); //method myc_int_delete(mtx); //destruktor myb_int_delete(tmp); //destruktor /*...*/ //MyC<int>* mtx = convert_data_to_MyC(data); WrapMyC_int mtx2 = myc_int_create_1(data); //other constructor //MyB<int>().Algorithm(mtx); WrapMyB_int tmp2 = myb_int_create(); //constructor myb_int_algorithm(tmp2, mtx2); //method myc_int_writetobuffer(mtx2, data); myc_int_delete(mtx2); //destructor myb_int_delete(tmp2); //destructor for (i = 0; i < 10; i++) printf("data[%d] = %d\n", i, data[i]); free(data); }//myb_wrapper.cpp
#include "myb_wrapper.h" #include "myc_wrapper.h" #include "MyB.h" //MyB<T> WrapMyB_int myb_int_create(void) { WrapMyB_int tmp; tmp.ptr = new MyB<int>(); return tmp; } void myb_int_algorithm(WrapMyB_int this_, WrapMyC_int arg) { MyB<int>* mb = static_cast<MyB<int>*> (this_.ptr); MyC<int>* mc = static_cast<MyC<int>*> (arg); mb->Algorithm(mc); } void myb_int_delete(WrapMyB_int this_) { MyB<int>* mb = static_cast<MyB<int>*> (this_.ptr); delete mb; this_.ptr = NULL; }//myb_wrapper.h
#ifndef MYWB #define MYWB #ifdef __cplusplus extern "C" { #endif #include "myc_wrapper.h" typedef struct WrapMyB_int_ { void* ptr; } WrapMyB_int; WrapMyB_int myb_int_create(void); void myb_int_algorithm(WrapMyB_int this_, WrapMyC_int arg); void myb_int_delete(WrapMyB_int this_); #ifdef __cplusplus } /*end extern "C"*/ #endif #endif//myc_wrapper.cpp
#include "myc_wrapper.h" #include "MyC.h" //MyC<T> WrapMyC_int myc_int_create(void) { WrapMyC_int tmp; tmp.ptr = new MyC<int>(); return tmp; } WrapMyC_int myc_int_create_1(int* data) { } void myc_int_writetobuffer(WrapMyC_int this_, int* buffer) { /* ... */ } void myc_int_delete(WrapMyC_int this_) { MyC<int>* mc = static_cast<MyC<int>*> (this_.ptr); delete mc; this_.ptr = NULL; }//myc_wrapper.h
#ifndef MYWC #define MYWC #ifdef __cplusplus extern "C" { #endif typedef struct WrapMyC_int_ { void* ptr; } WrapMyC_int; WrapMyC_int myc_int_create(void); WrapMyC_int myc_int_create_1(int* data); void myc_int_writetobuffer(WrapMyC_int this_, int* buffer); void myc_int_delete(WrapMyC_int this_); #ifdef __cplusplus } /*end extern "C"*/ #endif #endif#ifndef MyB_ #define MyB_ #include "MyC.h" template<class T> class MyB { public: MyB<T>() { mydata = new T[10]; } // do something with mtx void Algorithm(MyC<T>*& mtx) { for (int i= 0; i < 10; i++) mtx->data[i] = i; mtx->print(mtx); memcpy(mtx->data,mydata,10*sizeof(T)); } T* mydata; }; #endifund
#ifndef MyC_ #define MyC_ #include <iostream> #include <stdio.h> #include <string.h> template<class T> class MyC { public: MyC<T>() { data = new T[10]; memset(data, 0, 10*sizeof(T)); } ~MyC<T>() { delete [] data; } void print(MyC<int>* mtx); T* data; }; template<> inline void MyC<int>::print(MyC<int>* mtx) { // Hier z.B. mtx ausgeben oder andere // Dinge mit mtx tun... for (int i = 0; i <10; i++) std::cout << mtx->data[i] << std::endl; } #endifWarum kann ihc denn nicht casten?
-
argh...klar ich muss arg.ptr casten...
-
Wie setze ich denn aber das data array? bzw. den pointer in myc_wrapper.cpp ?
cih versuche das so:#include "myc_wrapper.h" #include "MyC.h" //MyC<T> WrapMyC_int myc_int_create(void) { WrapMyC_int tmp; tmp.ptr = new MyC<int>(); return tmp; } WrapMyC_int myc_int_create_1(int* data_) { WrapMyC_int tmp; tmp.ptr = new MyC<int>(); tmp.ptr.data = data_; return tmp; } void myc_int_writetobuffer(WrapMyC_int this_, int* buffer) { /* ... */ } void myc_int_delete(WrapMyC_int this_) { MyC<int>* mc = static_cast<MyC<int>*> (this_.ptr); delete mc; this_.ptr = NULL; }und erhalte
g++ -c myc_wrapper.cpp myc_wrapper.cpp: In function »WrapMyC_int myc_int_create_1(int*)«: myc_wrapper.cpp:14: Fehler: Abfrage des Elementes »data« in »tmp.WrapMyC_int_::ptr«, das vom Nicht-Klassentyp »void*« ist
-
Schreib dir für MyC einen Konstruktor der einen Zeiger vom Typ T* als Argument hat und ggf. den Inhalt des übergebenen Arrays in sein eigenes Array kopiert. Den rufst du dann auf. Der Pointer in MyC sollte eh nicht public sein (Kapselung)