Forum: Compiler & IDEs Global angelegtes Objekt in C++ funktioniert nicht


von Martin (Gast)


Lesenswert?

Hallo,

Folgendes Problem:
Global angelegte Instanzen funktioniern nicht.

Ich habe eine Klasse angelegt, mit einer öffentlichen Funktion. Es geht 
nicht um die Funktion der Klasse da diese nur zum Debuggen dient und 
daher sehr einfach gehalten ist.

Die Klasse sieht so aus:

Header:
1
class Test
2
{
3
  private:
4
  int al,bl;
5
  
6
  public:
7
  Test(int a, int b);
8
  void Write(int a, int b);
9
};

CPP
1
void Test::Write(int a, int b)
2
{
3
  al=a+1;
4
  bl=b+1;
5
}
6
7
Test::Test(int a, int b)
8
{
9
  Write(a, b);
10
}


Erzeuge ich eine Instanz der Klasse innerhalb einer Funktion dann 
funktioniert das auch einwandfrei.

Beispiel:
1
int main(void)
2
{
3
    Test t1(1,1);
4
    while (1) asm volatile("nop");
5
}

Erzeuge ich die Instanz global sieht es für mich so aus als ob die 
Rücksprungadresse für den Return nicht mehr passt und er springt 
irgendwo im Programm hin und das Programm läuft nicht mehr.

Beispiel:
1
Test t1(1,1);
2
3
int main(void)
4
{
5
   while (1) asm volatile("nop");
6
}


Muss man wenn man C++ verwendet noch spezielle Speicherbereiche 
initialisieren?

Oder ist das vielleicht ein Bug von g++ da OOP für µCs nicht vorgesehen 
ist?

Ich verwende AVRStudio 5.0
Würde mich für zahlreiche Ideen und Tipps freuen ;)

Der Fehler lässt sich mit dem angegebenen Quellcode nachstellen.

von Rolf M. (rmagnus)


Lesenswert?

Wie hast du den compilert und gelinkt? Hast du dafür gcc oder g++ 
verwendet?

von Martin (Gast)


Lesenswert?

Ich habe den avr-g++ verwendet. Im AVR Studio gibts auch extra ein 
Template für C++ Anwendungen. Es funktioniert auch wenn ich die Instanz 
lokal erzeuge.

von Andreas B. (andreasb)


Lesenswert?

Martin schrieb:
> Ich habe den avr-g++ verwendet. Im AVR Studio gibts auch extra ein
> Template für C++ Anwendungen. Es funktioniert auch wenn ich die Instanz
> lokal erzeuge.

Beim avr-g++ funktioniert auch noch einiges nicht, kannst du hier im 
Forum mal suchen...

Ich tippe auf Bug.

Nim C, du kannst auch in C "objektorientiert" programmieren. Ist 
ziemlich umständlich aber geht...

Gutes Beispiel: GLib oder GTK.


mfg Andreas

von Klaus W. (mfgkw)


Lesenswert?

Laut http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus 
sollte es eigentlich gehen.

Irgendwoe im Hinterkpof hatte ich aber mal gespeichert, daß die 
Initialisierung globaler Variablen nicht klappen soll, und einmal hatte 
ich es probiert bin undwar ebenfalls damit gescheitert.
Daraufhin bin ich auf eine lokale Variable ausgewichen und hatte 
vergessen, mich um den Grund zu kümmern.

Du bist jedenfalls nicht allein mit dem Problem.

von Klaus W. (mfgkw)


Lesenswert?

PS: Mein workaround war, die lokale Variable in main zu legen, und 
gleich am Anfang einen globalen Zeiger auf das lokale Objekt zu setzen.
Über den konnte dann der Rest des Programms damit arbeiten.

Wahrlich nicht schön, aber will man machen.

von Klaus W. (mfgkw)


Lesenswert?

Klaus Wachtler schrieb:
> bin undwar

oh gott

von Martin (Gast)


Lesenswert?

Hey vielen Dank Klaus!
zum einen ist der Link echt super! Und dein Workaround wird für mein 
eigendliches Programm auch anwendbar sein.
Gruß Martin

von (prx) A. K. (prx)


Lesenswert?

Mit einer älteren Version vom avr-gcc / avr-libc habe ich da nie 
Probleme gehabt. Allerdings habe ich das nicht mit aktuellen Versionen 
getestet.

Man muss bei solchen Initializern natürlich aufpassen, dass man darin 
(wie hier) nur das eigene Objekt anspricht und nicht noch andere 
statische Objekte oder irgendwelche noch nicht initialisierte I/O. Denn 
jedweder Initialisierungscode in main() ist zu diesem Zeitpunkt noch 
nicht gelaufen, die Interrupts sind abgeschaltet und die Reihenfolge des 
Aufrufs statischer Initializer ist unspezifiziert.

Was also oft nicht geht: Trace-Ausgaben bereits in Initializern 
auszuführen. Weil die Initialisierung vom dazu verwendeten Ausgabedevice 
noch nicht stattgefunden hat.

Ausserdem kann es sein, dass der Debugger einen seltsame Kontext 
anzeigt, denn die Initializer werden ja nicht aus main() heraus 
aufgerufen, sondern aus dem Initialisierungscode der avr-libc heraus.

von Martin (Gast)


Lesenswert?

Was vielleicht noch interessant zum Fehlerfinden sein kann:
Wenn ich Optimierung -O2 einstelle funktionierts auch mit der globalen 
Instanzierung. Ich weiß nur nicht genau was -O2 alles bewirkt...Mit -Os 
und -O0 funktionierts nicht.

von (prx) A. K. (prx)


Lesenswert?

Martin schrieb:

> Ich weiß nur nicht genau was -O2 alles bewirkt...

Steht dort haarklein aufgelistet. Kann man alle einzeln ein- oder auch 
nach -O2 wieder ausschalten, z.b. mit -O2 -fno-gcse
http://gcc.gnu.org/onlinedocs/gcc-4.5.3/gcc/Optimize-Options.html#Optimize-Options

von (prx) A. K. (prx)


Lesenswert?

Grad mal mit Studio 4 und 5 ausprobiert.

Mit Studio 4 funktioniert es, der Initialisierungsvektor wird erzeugt 
und der Initializer wird aufgerufen.

Mit Studio 5 (5.0.1163) funktioniert es nicht. Die Liste der 
Iniitialisierungsvektoren bleibt leer. Das .o File enthält keine 
entsprechende Section, auch die Debug-Sektionen fehlen.

Grund: Das Projekt-Template vom Studio 5 für C++ fehlt und das C 
Template verarbeitet .cpp Files nicht vergleichbar zu C Quellcode. Die 
Compiler-Optionen fehlen praktisch vollständig.

Abhilfe, Quick&Dirty: Endung .c verwenden und "-x c++"" hinzufügen, 
damit .c Files als C++ Files übersetzt werden (verified).

Oder eigenes Makefile verwenden. Oder C++ Template bauen. Vielleicht 
gibts auch andere Wege, das war mein erster Versuch mit dem Studio 5.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. schrieb:

> Abhilfe, Quick&Dirty: Endung .c verwenden und "-x c++"" hinzufügen,
> damit .c Files als C++ Files übersetzt werden (verified).

Die Endung ist mit -x egal. Lediglich die Reihenfolge spielt ne Rolle: 
-x muss vor den Dateien stehen.

von (prx) A. K. (prx)


Lesenswert?

Johann L. schrieb:

> Die Endung ist mit -x egal. Lediglich die Reihenfolge spielt ne Rolle:
> -x muss vor den Dateien stehen.

Dem Compiler ist es egal, aber dem Builder vom Studio nicht. Wenn das 
File nicht auf .c endet, dann wird ein ungeeignetes Makefile erzeugt und 
der Compiler falsch aufgerufen:
1
./%.o: .././%.c
2
  @echo Building file: $<
3
  @echo Invoking: AVR/GNU C Compiler
4
  $(QUOTE)$(AVR_APP_PATH)avr-gcc.exe$(QUOTE) -funsigned-char -funsigned-bitfields -O0 -fpack-struct -fshort-enums -g3 -Wall -c -std=gnu99 -x c++  -mmcu=atmega16   -MD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
5
  @echo Finished building: $<
6
7
./%.o: .././%.cpp
8
  @echo Building file: $<
9
  @echo Invoking: AVR/GNU CPP Compiler
10
  $(QUOTE)$(AVR_APP_PATH)avr-g++.exe$(QUOTE)   -MD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o"$@" "$<"
11
  @echo Finished building: $<

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.