Hallo,
Ich programmiere gerade mit eine LPCXPresso Board in C++.
Sobald ich eine abstrakte Klasse definiere bindet der Compiler einen
ganzen Rattenschwanz von Stringverarbeitung ein, bis der Linker bei
_write, _close, etc. scheitern muss.
1
classLed{
2
public:
3
virtualColorxyYconst&getColor(void)const=0;
4
}
Hier mein aktueller Workaround, den ich gerne vermeiden möchte.
FelixW schrieb:> Sobald ich eine abstrakte Klasse definiere bindet der Compiler einen> ganzen Rattenschwanz von Stringverarbeitung ein, bis der Linker bei> _write, _close, etc. scheitern muss.
Ist nur geraten, aber einen Versuch wert.
Ich schätze mal das Problem liegt darin, dass der Compiler
Funktionalität einbindet, die darin besteht für diese pure/virtual
Funktion eine Default Implementierung zu generieren, die dich davon in
Kenntnis setzt, dass eine pure/virtual Funktion unzulässigerweise
aufgerufen wurde.
Verpass der Funktion mal eine Implementierung und sieh nach, ob dann der
Rattenschwanz immer noch dazugezogen wird
>
1
>classLed{
2
>public:
3
>virtualColorxyYconst&getColor(void)const=0;
4
>}
ColorxyY const & LED::getColor()
{
}
Ja, man kann durchaus auch für pure Funktionen eine Implementierung
angeben!
Mein Compiler lässt nicht eine abstrakte Definition und Implementierung
in der selben Klasse zu.
Ich habe eine Lösung gefunden:
1
extern"C"void__cxa_pure_virtual(){while(1);}
Die Funktion __cxa_pure_virtual() ist in libstdc++ definiert und wird
aufgerufen sobald ich eine abstrakte Methode aufrufe. Sie gibt die
Meldung "pure virtual call" aus.
Die extra 60kB, sind vor allem malloc() geschuldet.
Mit obigen Aufruf wird jetzt gegen meine eigene Funktion gelinkt, keine
Ahnung, ob das zu zulässig / günstig ist. Der Linker jedenfalls schluckt
es. :)
Danke
Felix
FelixW schrieb:> Die extra 60kB, sind vor allem malloc() geschuldet.Das glaube ich nun kaum. So umständlich und groß kann man ein
simples malloc() gar nicht implementieren.
Die von dir genannten externen Symbole, die dann referenziert werden,
deuten vielmehr darauf hin, dass standardmäßig da irgendwas
eingebaut wird, was dann per stdio (bzw. seinem C++-Pendant) bei
Bedarf eine Ausschrift auf stderr bringen kann. Finde heraus, wer
das ist und was er tun will, und du solltest in der Lage sein,
einen für dich besser passenden Ersatz zu schreiben.
(stdio seinerseits zieht natürlich noch malloc() nach für die
potenzielle Pufferung der Daten, aber das dürfte da kaum den
Löwenanteil am Overhead machen.)
FelixW schrieb:> Mein Compiler lässt nicht eine abstrakte Definition und Implementierung> in der selben Klasse zu.
Eigenartig.
Das sollte eigentlich keinen Compiler vor große Probleme stellen.
Allerdings Achtung: Du kannst nicht (standardkonform) die
Funktionsdefinition direkt in der Klassendeklaration angeben.
Das hier ist illegal
1
classLed{
2
public:
3
virtualColorxyYconst&getColor(void)const=0{};
4
};
Du musst schon eine eigene Funktion dafür schreiben
1
classLed{
2
public:
3
virtualColorxyYconst&getColor(void)const=0;
4
};
5
6
ColorxyYconst&LED::getColor()const
7
{
8
}
Falls du noch Interesse daran hast, poste mal eine Testprogramm welches
bei dir nicht compiliert, die Fehlermeldung dazu. Vielleicht findet sich
ja ein ganz anderes Problem, welches du missverstanden hast.
(Ich seh nämlich gerade, dass ich das Funktions-const in der
Implementierung weiter oben vergessen habe. Aber das hätte eigentlich
aus der Fehlermeldung ersichtlich sein sollen)
Denn wie gesagt: Wenn dein Compiler einigermassen standardkonform ist,
dann muss das gehen. Es gibt ja auch keinen wirklich schwerwiegenden
technischen Grund, warum das nicht möglich sein sollte.
FelixW schrieb:> Ich habe eine Lösung gefunden:extern "C" void __cxa_pure_virtual() {> while (1); }Jörg Wunsch schrieb:> Finde heraus, wer> das ist und was er tun will, und du solltest in der Lage sein,> einen für dich besser passenden Ersatz zu schreiben.
Der Overhead kommt vom Exception-Handling (Stack-Undwinding,
Unwinding-Tables, Generierung der Fehlermeldung), welches wiederum
malloc(), String-Verarbeitungen, und Konsolen-Output (_write) benötigt.
Falls du tatsächlich die gesamte Fehlermeldung der Exception haben und
ausgeben möchtest (über UART oder so) dann musst du _write und die
anderen implementieren, ja. Falls du aber die Exception gar nicht haben
möchtest, ist die Implementierung von __cxa_pure_virtual der richtige
Ansatz, dann kannst du deine eigene Behandlung verwenden (wie eben
while(1) aka Controller-Freeze; kannst ja noch ein __disable_irq ()
dazuschreiben).
In der Embedded-Entwicklung können 60kB mehr oder weniger den Ausschlag
geben, weswegen es sinnvoll sein kann den riesigen Overhead durch das
Exception-Handling zu vermeiden, anstelle von sie "richtig" zu verwenden
und die Meldung irgendwo auszugeben.
nur nicht in den Header schreiben :/
@Jörg Wunsch:
Asche auf mein Haupt. Man sollte mit den Zeilen im map-File nicht
durcheinander kommen.
"malloc() ist klein, sobald ich "new" im Code verwende bläht sich der
Code auf.
Ich mache dafür aber ein neues Thema auf.
FelixW schrieb:> compiliert :).
Super.
Dann ist mein Weltbild wieder hergestellt.
Wobei ich persönlich ebenfalls die Variante mit dem 'überschreiben' der
1
extern"C"void__cxa_pure_virtual(){while(1);}
wählen würde.
Die Endlosschleife ist diskussionswürdig, da würde ich für mich
irgendwas eindeutigeres wünschen um auch an der Schaltung erkennen zu
können, das dieser Fall eingetreten ist. Aber grundsätzlich hätte ich
keine Probleme mit so einer Lösung.
> Asche auf mein Haupt. Man sollte mit den Zeilen im map-File nicht> durcheinander kommen.> "malloc() ist klein, sobald ich "new" im Code verwende bläht sich der> Code auf.
Einigen wir uns darauf: Wird 1 Systemfunktion inkludiert, dann zieht das
einen Rattenschwanz an anderen Funktionen nach sich, die allesamt
inkludiert werden müssen. Denn eines darf man nie vergessen: Oftmals ist
die eigentliche Funktionalität eigentlich recht trivial, aber
Fehlerbehandlung und vor allen Dingen Fehlerkommunikation mit dem
Benutzer bläht Funktionen (und deren Folgefunktionen ... und deren
Folgefunktionen) oftmals enorm auf.
Dr. Sommer schrieb:> FelixW schrieb:> Falls du aber die Exception gar nicht haben> möchtest, ist die Implementierung von __cxa_pure_virtual der richtige> Ansatz,
In dem Fall ist die Compileroption -fno-exceptions das geeignete Mittel
der Wahl.
Oliver
Oliver schrieb:> In dem Fall ist die Compileroption -fno-exceptions das geeignete Mittel> der Wahl.
Ja, aber nur wenn die Exceptions im eigenen Code geworfen werden; auf
den bereits vorkompilierten Code der libstdc++ , welcher normalerweise
eben die __cxa_pure_virtual enthält, hat das keinen Einfluss, somit
würde bei verwendung virtueller Funktionen der ganze Rattenschwanz
trotz -fno-exceptions eingebunden. Was eber nicht heißt dass man
-fno-exceptions nicht benutzen soll/muss...
Karl Heinz Buchegger schrieb:> Die Endlosschleife ist diskussionswürdig
Die ist wunderbar, da kann man im Debugger unterbrechen und sieht sofort
woran es hapert.