Wie können Sie C++ ausführen, wenn Ihr eingebetteter Compiler keine Operator New- oder STL-Unterstützung bietet?

StackOverflow https://stackoverflow.com/questions/765459

Frage

Ich arbeite an einem Gruppenprojekt für meine Universität und bin beim Versuch, meinen Code zum Laufen zu bringen, auf eine große Hürde gestoßen.

Der Compiler, den wir für unseren 8-Bit-Atmel-Mikrocontroller haben, unterstützt weder die Operatoren „new“ oder „delete“ noch die C++-STL.Ich könnte es in C programmieren, aber ich muss einen A*-Algorithmus implementieren, was ich noch nie zuvor gemacht habe.Obwohl ich zunächst C ausprobiert habe, wurde mir bald klar, dass ich noch nie reines C gemacht hatte.Der Versuch, Objekte mit Strukturen und Funktionen zu modellieren, verlangsamt mich, da ich an die viel sauberere C++-Syntax gewöhnt bin.

Unabhängig davon finden Sie hier den genauen Wortlaut für die Mängel meines Compilers: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus

Um sie zu überwinden und trotzdem C++ zu verwenden, habe ich die folgenden Möglichkeiten in Betracht gezogen.1) Weisen Sie nichts zu, sondern verwenden Sie einfach Vorlagen, um feste Arrays auf dem Stapel zu generieren.2) Weisen Sie zu und finden Sie einen Hack, um den Konstruktor für Objekte aufzurufen, sobald ich den Platz für sie zugewiesen habe.Die Platzierung „Neu“ ist keine Option, da „Neu“ kein Operator ist.3) Benutze einfach C und saug es auf, es ist ein Mikrocontroller, warum werde ich Lust?4) Finden Sie einen besseren Compiler, der wahrscheinlich $$$ kosten wird.

Die zweite Option ist die schwierigste, würde sich aber hinsichtlich der Art und Weise, wie ich diesen Code schreiben kann, am meisten auszahlen.Allerdings kann ich mir vorstellen, dass das Debuggen sehr mühsam sein könnte, wenn ich etwas falsch mache.Ich denke darüber nach, Objekte auf dem Stapel zu erstellen, ihre Bits in den zugewiesenen Speicherplatz zu kopieren und dann die Bits im Objekt auf Null zu setzen, damit es seinen Destruktor nicht aufruft.Dazu würde ich mit einem vorzeichenlosen Zeichenzeiger und dem Operator „sizeof“ direkt auf die Bits zugreifen, um die Byteanzahl zu ermitteln.

Das klingt schrecklich und ich weiß nicht, ob es zuverlässig funktionieren könnte, aber ich denke darüber nach.Ich weiß, dass vtables ein Problem sein können, aber ich habe nicht vor, vtables zu haben, da es sich nur um einen 8-Bit-Mikrocontroller handelt.

War es hilfreich?

Lösung

Nur für das Protokoll, werden die Bits in einem Objekt Nullstellung nicht beeinflussen, ob die destructor aufgerufen wird (es sei denn, der Compiler eine besondere Eigenart hat, die dieses Verhalten ermöglicht). Schreiben Sie einfach einige Logging-Anweisungen in Ihrer destructor dies aus zu testen.

Die Strukturierung Ihres Programms nicht zu irgendetwas zuteilen ist wahrscheinlich die Art und Weise wurde das System entwickelt. Ich habe nicht mit eingebetteten Systemen gearbeitet, bevor, jedoch habe ich einige erfahrenen eingebettete Läden lesen, die Verwendung von dynamischen Speichern entmutigen, weil die Laufzeitumgebung knappe Mengen davon hat.


Allerdings, wenn es sein muss, können Sie immer noch die Platzierung neuer verwenden. Wenn Sie nicht die <new> Header haben, hier sind die entsprechenden Zeilen direkt von ihm auf meine Version von GCC:

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }

Stick, der irgendwo in einer Header-Datei von jeder Quelldatei enthalten, die Platzierung neue / Löschen verwendet.

Beispieldatei, die diese Tests:

#include <cstdio>
#include <new>

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    char foobar[16];
    cstr* str = new (&foobar) cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    str->~cstr();
}

Auf meiner Version von GCC, diese nicht verwendet libstdc++ überhaupt (wenn -fno-exceptions verwendet wird).


Wenn Sie nun, dass mit malloc (wenn Ihre Plattform bietet diese) kombinieren möchten, dann können Sie dies tun:

#include <cstdio>
#include <cstdlib>

inline void* operator new  (std::size_t n) {return std::malloc(n);}
inline void* operator new[](std::size_t n) {return std::malloc(n);}
inline void  operator delete  (void* p) {std::free(p);}
inline void  operator delete[](void* p) {std::free(p);}

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    cstr* str = new cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    delete str;
}

Auf diese Weise können Sie die Standard-new / delete verwenden, die Sie mit vertraut sind, ohne Verwendung von libstdc++ erforderlich ist.

Viel Glück!

Andere Tipps

Sie kämpfen nicht Ihre Werkzeuge. Wenn der einzige Compiler für Embedded Systems haben einen C-Compiler ist, lernen C - es ist nicht schwierig. einige bastardised Version der beiden Sprachen zu produzieren nur versuchen, eine ziemlich einfache Programmierung Problem zu lösen, wird nur Ende in Tränen aus.

einen anderen Weg, es zu betrachten, wenn Ihre Embedded-Plattform nicht einmal einen C-Compiler unterstützt hat, aber nur einen Assembler, wäre Ihr erster Impuls sitzen zu hin und schreibe einen C ++ Compiler in Assembler? Ich hoffe nicht, ich hoffe, Sie würden stattdessen hinsetzen und lernen, zu verwenden der Monteur Ihre Aufgabe abzuschließen -. einen C ++ Compiler (oder sogar einen C-Compiler) Schreiben völlig ungeeignet Nutzung Ihrer Zeit wäre, und zu einem Ausfall an Sicherheit grenzender Wahrscheinlichkeit führen würde

Ich denke, Sie gehen das Problem von einem Standpunkt aus an, der nicht optimal ist.

Sie konzentrieren sich auf den Compiler (oder dessen Fehlen), anstatt sich auf die HARDWARE zu konzentrieren.

Die wahrscheinlichste Antwort auf Ihre Hauptfragen lautet: „Weil die Hardware all diese C++-Sachen nicht unterstützt.“Eingebettete Hardware (Mikrocontroller) zeichnet sich durch die Anpassung des Hardwaredesigns aus – Speicherzuordnungen, Interrupt-Handler, I/O usw.

Meiner Meinung nach sollte man sich ZUERST etwas Zeit mit dem Hardware-Buch für den Mikrocontroller nehmen und sich mit den Besonderheiten des Geräts vertraut machen – d. h.wie es entworfen wurde und für welchen Hauptzweck.Einige wurden für die schnelle Speichermanipulation entwickelt, andere für die schnelle E/A-Verarbeitung, einige für A/D-Arbeiten und einige für die Signalverarbeitung.Der Typ des Mikrocontrollers bestimmt die Assembler-Anweisungen, die er dafür geschrieben hat, und diese bestimmen, was ein Compiler auf höherer Ebene effizient tun kann.

Wenn dies wichtig ist, nehmen Sie sich etwas Zeit und schauen Sie sich auch den Assembler an – er wird Ihnen sagen, was den Designern wichtig war.Es verrät Ihnen auch viel darüber, wie viel Sie mit einem High-Level-Compiler erreichen können.

Im Allgemeinen unterstützen Mikrocontroller C++ nicht, da sich das Design wirklich nicht um Objekte oder eine ausgefallene Speicherverwaltung kümmert (aus C++-Perspektive).Das ist machbar, aber oft versucht man, einen runden Pflock in ein quadratisches Loch zu schlagen, um Konstruktoren und Destruktoren (sowie „Neu“ und „Löschen“) in der Mikroumgebung zum Laufen zu bringen.

WENN Sie einen C-Compiler für dieses Gerät haben, betrachten Sie das als einen Segen.Ein guter C-Compiler ist oft „mehr als genug“, um hervorragende Embedded-Software zu erstellen.

Prost,

-Richard

Nur weil es nicht diese Werkzeuge hat, bedeutet nicht, dass Sie nicht von C ++ profitieren können. Wenn das Projekt groß genug ist, um Zugang zu Oriented Design-Objekt allein sein könnte Motivation genug.

Wenn es nicht unterstützt ‚neue‘ dann ist es wahrscheinlich, weil es keinen Sinn macht, eine automatische Unterscheidung zwischen einem Haufen zu machen und dem Stapel. Dies könnte aufgrund Ihrer Speicherkonfiguration sein. Es könnte auch sein, da Speicherressourcen, so dass nur sehr vorsichtig Zuteilung eingeschränkt sind sinnvoll. Wenn Sie unbedingt Ihre eigene ‚neuen‘ Betreiber haben zu implementieren, könnte man sich in Anpassung Doug Lea malloc . Ich glaube, er begann sein allocator in einer ähnlichen Situation (Neuimplementierung C ++ ist neu).

Ich liebe die STL, aber es ist immer noch möglich, ohne dass es sinnvoll, Dinge zu tun. Je nach Umfang des Projektes könnten Sie besser dran, nur ein Array verwendet wird.

Ich hatte einen ähnlichen Compiler, der eine bizarre Version des Embedded-C ++ Standard . Wir hatten operator new die Konstrukteure für uns anrufen würde und Destruktoren wurden genannt in den meisten Fällen . Der Compiler / runtime Verkäufer gingen und umgesetzt try und catch mit setjmp und longjmp als Komfort für den Ingenieur . Das Problem war, dass sie nie erwähnt, dass ein throw nicht Destruktoren der lokalen Objekte verursachen würde aufgerufen werden!

Wie auch immer, unsere Gruppe die Code-Basis geerbt, nachdem jemand eine Anwendung geschrieben handeln, wie es Standard C ++ war: mit RAII Techniken und alle anderen Güte. Am Ende haben wir erneut zu schreiben, was eine Reihe von rufen Sie uns an objektorientierten C statt. Sie könnten nur beißen die Kugel und das Schreiben in gerade C. Statt Konstrukteure haben eine explizit genannt Initialisierungsmethode zu betrachten. Destruktoren wird eine explizite Abbruchmethode genannt. Es gibt nicht viel von C ++, die Sie nicht ziemlich schnell in C nachahmen können. Ja, MI ist ein Schmerz in der ... aber einfache Vererbung ist recht einfach. Schauen Sie sich auf dieser PDF für einige Ideen. Es beschreibt fast den Ansatz, den wir haben. Ich wünschte wirklich, ich hatte unsere Methode abgeschrieben irgendwo ...

Sie können einigen hilfreichen Code auf meiner A * Tutorial Website . Obwohl der Code ich dies in STL unterstützen schrieb verwendet, sollte sein leicht aus der STL-Unterstützung strippen. Darüber hinaus gibt es einen Pool Allocator mit ihm eingeschlossen (fsa.h), die ich schrieb STL auf Spielkonsolen zu beschleunigen. Es ist C ++ Code, aber ich portierte es ursprünglich von C, und ich glaube nicht, dass es schwer sein würde, es in die andere Richtung zu tun. Der Code wird von mehr als 10.000 Menschen getestet, so dass es eine gute Basis ist aus zu starten.

Ersetzen der STL Strukturen Ich verwende ist kein Problem, da es zu Vektoren beschränkt ist. Ich verwende einen der Vektoren als Prioritätswarteschlange der Heap Funktionen (make_heap und push_heap). Sie können das ersetzen mit meinem altem C-Code rel="nofollow, die eine Prioritätswarteschlange hat in C implementiert, die in den Code einfach fallen sollte. (Die nur ein alloc der Fall ist, so dass Sie, dass mit einem Zeiger auf einen reservierten Bereich des Speichers ersetzen.

Wie Sie in diesem Codefragment aus dem Header sehen können, ist der Hauptunterschied in C-Code, dass es keine ist dieser Zeiger, kein Objekt, so normalerweise Ihr Code einen Objektzeiger als erstes Argument nimmt.

void PQueueInitialise( PQUEUE *pq, int32 MaxElements, uint32 MaxRating, bool32 bIsAscending );
void PQueueFree( PQUEUE *pq );
int8 PQueuePush( PQUEUE *pq, void *item,  uint32 (*PGetRating) ( void * ) );
int32 PQueueIsFull( PQUEUE *pq );
int32 PQueueIsEmpty( PQUEUE *pq );
void *PQueuePop( PQUEUE *pq, uint32 (*PGetRating) ( void * ) );

Warum es nicht zuerst auf Ihrem Desktop-Computer schreiben, unter Berücksichtigung der Beschränkungen des Compilers, debuggen, stellen Sie sicher, dass es funktioniert perfekt und dann erst mit der eingebetteten Umgebung bewegen?

, wenn eingebettete Arbeit zu tun, kann ich einmal nicht einmal verbinden die C-Laufzeit für Speichereinschränkungen, aber die Hardware hatte eine DMA (dynamische Speicherzuweisung) Anweisung so schrieb ich meine eigenen malloc mit dieser Hardware, Hardware hat wahrscheinlich ein ähnliche Funktion, so können Sie einen malloc schreiben und dann ein neues auf der malloc basiert.

Wie auch immer am Ende habe ich 99% Stapelzuordnungen, und ein paar Grenzen setzen os statische Objekte, die ich recycelt würde, indem anstelle builiding. Dies könnte mir eine gute Lösung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top