www.mikrocontroller.net

Forum: GCC C++ auf AVR: new und virtuelle Methoden


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Detlev T. (detlevt)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Hallo Leute,

ich habe hier ( Beitrag "c++ new und delete" ) eine 
Methode gefunden, wie man den ab Werk nicht vorhandenen new-Operator für 
den GCC nachrüstet. Ich bin mir aber nicht sicher, ob diese Krücke auch 
dann noch funktioniert, wenn man Objekte mit virtuellen Methoden damit 
erzeugt.

Schon 'mal gemacht? Geht's?

Vielen Dank für eure Antworten.

Gruß, DetlevT

Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:

> Schon 'mal gemacht? Geht's?

Was hindert dich daran, es auszuprobieren?

#include <avr/io.h>

class A
{
  public:
    virtual void doit()   { PORTB |= ( 1 << PB0); }
};

class B : public A
{
  public:
    virtual void doit()   { PORTB |= ( 1 << PB1 ); }
};

void foo( A* obj )
{
  obj->doit();
}

int main()
{
  DDRB = 0x03;
  PORTB = 0x00;

  B objB;

  foo( &objB );

  while( 1 )
    ;
}

wenn virtuelle Funktionen funktionieren, dann tut sich was am Pin PB1. 
Wenn nicht, dann am Pin PB0.

Es gibt Dinge, die hat man mit einem Testprogramm schneller geklärt, als 
man in einem Forum die entsprechende Frage eingetippt hat. Und dann weiß 
man es sogar ganz genau :-)

PS: was haben eigentlich virtuelle Funktionen damit zu tun, wie das 
Objekt erzeugt wurde? Alles was man braucht, ist ein Pointer aufs Objekt 
um virtuelle Aufrufe zu triggern. new hat damit erst mal genau gar 
nichts zu tun.

Autor: Marco M. (marco_m)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Das ist ein Workaround, wenn man eben was portieren will. Das "richtige" 
new macht mehr. Es ruft new_handler auf, wenn Speicher alle ist, wirft 
bad_alloc() wenn danach keiner da ist usw. Dein Workaround gibt einen 
NULL Pointer zurück, wenn der Speicher alle ist. Das ist nicht erlaubt. 
Ausserdem brauchst du noch eine Implementation operator new[] und 
operator delete[].

Ohne Exceptions kannst du jedenfalls keinen standardkonformen operator 
new implementieren, sondern nur die Variante "operator new(std::size_t 
st,const std::nothrow_t &) throw();" - der im Fehlerfalle einen 
null-pointer zurückgibt.

"new" soll das Objekt nicht initialisieren, sondern nur den Speicher 
bereitstellen, virtuelle Funktionen gehen daher, weil die Strukturen vom 
Objektkonstruktor aufgebaut werden.

Autor: Detlev T. (detlevt)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@Karl Heinz
Hast du die Frage überhaupt gelesen? Es geht um einen Würg-Around für 
den nicht vorhandenen new-Operator. Der taucht in deinem Listig ja gar 
nicht auf.

@Marco
Danke für deine Antwort. Das wollte ich wissen. Und jetzt verstehe ich 
sogar, warum dieser Würg-Around nicht standardmäßig bei avr-gcc dabei 
ist.

Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> @Karl Heinz
> Hast du die Frage überhaupt gelesen? Es geht um einen Würg-Around für
> den nicht vorhandenen new-Operator. Der taucht in deinem Listig ja gar
> nicht auf.

Nö.
Es geht darum, ob virtuelle Funktionen funktionieren.
Lies doch deine Frage noch mal!

Und dann erklär mir mal, was virtuelle Funktionen mit new zu tun haben 
sollen!
Und selbst wenn, und ich betone "wenn", es da einen dubiosen 
Zusammenhang geben könnte (der nicht existiert, weil das eine mit dem 
anderen nichts zu tun hat), was hindert dich daran, aus
  B objB;

  foo( &objB );

ein
  B* objB = new B;

  foo( objB );

zu machen.

Richtig. Nichts.
Ausser das DU es tun müsstest.

Autor: Detlev T. (detlevt)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@Karl Heinz
Nimm das bitte nicht persönlich! Es geht NICHT darum, ob virtuelle 
Methoden generell funktionieren, sondern nur ob sie mit Objekten 
funktionieren, die mit diesem nicht konformen new-Würgaround erzeugt 
wurden.

Ich kenne mich mit den Interna von C+-Compilern nicht aus. Wenn ich 
"new" schreibe, muss irgendeine Routine 1.) Speicherplatz reservieren, 
2.) Die Zeiger auf die virtuellen Methoden dort eintragen. Ob letzteres 
die Aufgabe von "new" ist, wusste ich bis vor kurzem nicht. In dem von 
mir angegebenen Thread wurden nur Objekte ohne virtuelle Methoden 
verwendet.

Natürlich kann man auch alles selbst ausprobieren, die Fehler suchen, 
die andere schon gesucht haben und am Ende vielleicht sogar die Lösungen 
finden, auf die andere schon längst gekommen sind. Ich finde es aber 
ganz gut, dass es mit diesem Forum auch einen anderen Weg gibt.

Gruß, DetlevT

Autor: C++ (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
C++ Objekte mit virtuellen Methoden haben doch (in irgend einer Form) 
eine Zeiger auf die konkrete Methoden-Tabelle (ein Array von 
Methoden-Addressen).
Diesen Ptr richtig zu initialisieren kann aber nur der Konstruktor der 
konkreten Klasse.
-> "::new()" kann das garnicht leisten.
-> wie (komfortabel,fehlersicher,...) auch immer man den Speicher 
allokiert,
   sobald man ihn hat, macht der GCC den Rest.

Autor: C++ (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
BTW: AVR-GCC legt diese Tabellen leider im RAM ab. Kein wirklich großes 
Problem, nur ist RAM auf AVR's immer knapp und leider nicht "const", 
d.h. kleine Schreibfehler auf diese Tabellen haben event. große 
Auswirkung auf den weiteren Programmablauf ;-)

Autor: Marco M. (marco_m)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
C++ schrieb:
> BTW: AVR-GCC legt diese Tabellen leider im RAM ab. Kein wirklich großes
> Problem, nur ist RAM auf AVR's immer knapp und leider nicht "const",
> d.h. kleine Schreibfehler auf diese Tabellen haben event. große
> Auswirkung auf den weiteren Programmablauf ;-)

Oh ja, das ist wichtig. Wenn man nämlich von einer Basisklasse mit 
virtuellen Membern ableitet, dann wird die komplette vtable der 
Basisklasse mindestens dupliziert. Auf diese Weise ist der SRAM schnell 
voll.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Karl Heinz Buchegger schrieb:

> wenn virtuelle Funktionen funktionieren, dann tut sich was am Pin PB1.
> Wenn nicht, dann am Pin PB0.

Mit den richtigen Optimierungen erzeugt avr-gcc für einen 
ATmega32 folgendes:
 
main:
  ldi r24,lo8(3)
  out 0x17,r24
  out 0x18,__zero_reg__
  sbi 0x18,1
.L4:
  rjmp .L4

Es funktioniert also.

Autor: Carl Drexler (Firma: nn) (jcw2)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Was auch zeigt, wie "riesig" der C++ Overhead sein kann ;-)

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Carl Drexler schrieb:
> Was auch zeigt, wie "riesig" der C++ Overhead sein kann ;-)

Oder wie gut GCC sein kann, wenn man die richtigen Optionen wählt :-)

Für C++ gibt's aber auch genügend Beispiele, wie man ohne großen Auswand 
den Flash füllt oder gar den RAM.  Wieder sind virtuelle Methoden ein 
Beispiel, die manche Entwickler selbst auf 32-Bit Embedded-Systemen als 
obsolet betrachten...

Autor: Carl Drexler (Firma: nn) (jcw2)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
> Oder wie gut GCC sein kann, wenn man die richtigen Optionen wählt :-)

Es wird aber oftmals behauptet, daß C++ immer riesig sein muß. Was, wie 
man sehen kann, nicht stimmt. Das wollte ich nur anmerken.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Carl Drexler schrieb:
> Johann L. schrieb:
>> Oder wie gut GCC sein kann, wenn man die richtigen Optionen wählt :-)
>
> Es wird aber oftmals behauptet, daß C++ immer riesig sein muß.

Naja, bei so einem trivialen Programm darf man von dieser Behauptung 
auch kleinere Abstriche machen.

Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
> Karl Heinz Buchegger schrieb:
>
>> wenn virtuelle Funktionen funktionieren, dann tut sich was am Pin PB1.
>> Wenn nicht, dann am Pin PB0.
>
> Mit den richtigen Optimierungen erzeugt avr-gcc für einen
> ATmega32 folgendes:
>  
>
> main:
>   ldi r24,lo8(3)
>   out 0x17,r24
>   out 0x18,__zero_reg__
>   sbi 0x18,1
> .L4:
>   rjmp .L4
> 
>
> Es funktioniert also.

:-)
Das ist fies. Ist ja alles geinlined worden :-)

Autor: Rolf Magnus (rmagnus)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> Natürlich kann man auch alles selbst ausprobieren, die Fehler suchen,
> die andere schon gesucht haben und am Ende vielleicht sogar die Lösungen
> finden, auf die andere schon längst gekommen sind. Ich finde es aber ganz
> gut, dass es mit diesem Forum auch einen anderen Weg gibt.

Du sollst ja keinen Fusionsreaktor erfinden, sondern nur probieren, ob 
virtuelle Memberfunktionen gehen. Wenn ja, hast du deine Antwort 
innerhalb von 5 Minuten, wenn nein, kannst du immer noch im Forum 
nachfragen, warum es nicht geht und wie man das behebt.

Autor: Roland H. (batchman)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
> Mit den richtigen Optimierungen erzeugt avr-gcc für einen
> ATmega32 folgendes:

Karl Heinz Buchegger schrieb:
> Das ist fies. Ist ja alles geinlined worden :-)

Oha. Johann, welche Optimierungen waren denn das bitte? Mit -03 bei GCC 
4.6.2 konnte ich das nicht nachvollziehen. Hat er die vtable komplett 
eliminiert?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Roland H. schrieb:
> Oha. Johann, welche Optimierungen waren denn das bitte?

-Os -fwhole-program genügt bei mir.

Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Roland H. schrieb:

> Hat er die vtable komplett
> eliminiert?

Ja, hat er.
GCC hat rausgefunden, dass der dynamische Typ innerhalb foo() ein 'class 
B' ist, und er damit den Aufruf direkt und nicht virtual machen kann. 
Damit gibt es aber keine Referenz mehr auf die vtable und die kann dann 
wiederrum vom Linker entfernt bzw. gar nicht eingelinkt werden.

Und dabei wollte ich ihm alles so schön in einer Funktion verstecken, 
damit genau das nicht passiert :-)

Autor: Roland H. (batchman)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
>> Oha. Johann, welche Optimierungen waren denn das bitte?
>
> -Os -fwhole-program genügt bei mir.

Bei mir immer noch kein Erfolg. Welcher GCC kam zum Einsatz?

Bei mir steht am Ende folgendes im .lss:
000000a6 <A::doit()>:
  a6:   28 9a           sbi     0x05, 0 ; 5
  a8:   08 95           ret

000000aa <B::doit()>:
  aa:   29 9a           sbi     0x05, 1 ; 5
  ac:   08 95           ret

000000ae <main>:
  ae:   cf 93           push    r28
  b0:   df 93           push    r29
  b2:   00 d0           rcall   .+0             ; 0xb4 <main+0x6>
  b4:   cd b7           in      r28, 0x3d       ; 61
  b6:   de b7           in      r29, 0x3e       ; 62
  b8:   83 e0           ldi     r24, 0x03       ; 3
  ba:   84 b9           out     0x04, r24       ; 4
  bc:   15 b8           out     0x05, r1        ; 5
  be:   84 e0           ldi     r24, 0x04       ; 4
  c0:   91 e0           ldi     r25, 0x01       ; 1
  c2:   9a 83           std     Y+2, r25        ; 0x02
  c4:   89 83           std     Y+1, r24        ; 0x01
  c6:   ce 01           movw    r24, r28
  c8:   01 96           adiw    r24, 0x01       ; 1
  ca:   0e 94 55 00     call    0xaa    ; 0xaa <B::doit()>
  ce:   ff cf           rjmp    .-2             ; 0xce <main+0x20>

Kompiliert mit
/home/gcc-avr-4.6.2/data/gcc-toolchains-precompiled/avr/avr8-gnu-toolchain-3.4.0.663/bin/avr-gcc -mmcu=atmega328p -DF_CPU=16000000ul -Wall -Os -fwhole-program -o build/demo-cplusplus-4.o -c ../../../../common/apps/demo-cplusplus-4/src/demo-cplusplus-4.cpp

/home/gcc-avr-4.6.2/data/gcc-toolchains-precompiled/avr/avr8-gnu-toolchain-3.4.0.663/bin/avr-gcc -mmcu=atmega328p -o build/demo-cplusplus-4-atmega328p-4.6.2.elf build/demo-cplusplus-4.o

/home/gcc-avr-4.6.2/data/gcc-toolchains-precompiled/avr/avr8-gnu-toolchain-3.4.0.663/bin/avr-gcc --version
avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.0_663) 4.6.2

Karl Heinz Buchegger schrieb:
> Und dabei wollte ich ihm alles so schön in einer Funktion verstecken,
> damit genau das nicht passiert :-)

Tja, der GCC kann's keinem recht machen :-) Ich möchte, dass genau das 
bei mir passiert :-)

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Roland H. schrieb:
>> -Os -fwhole-program genügt bei mir.
>
> Bei mir immer noch kein Erfolg. Welcher GCC kam zum Einsatz?

4.7.2

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Roland H. schrieb:

> Oha. Johann, welche Optimierungen waren denn das bitte?

avr-gcc 4.8 mit -flto -O2, sollte aber auch mit 4.7 gehen.

Autor: Carl Drexler (Firma: nn) (jcw2)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
AVR-gcc 4.8?
Darf man den schon richtig benutzen ;-)

Autor: Rolf Magnus (rmagnus)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Karl Heinz Buchegger schrieb:
> Und dabei wollte ich ihm alles so schön in einer Funktion verstecken,
> damit genau das nicht passiert :-)

Dann mußt du der Funktion noch das Attribut noinline geben. Wäre doch 
gelacht, wenn wir dem nicht unseren Willen aufzwingen könnten.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Carl Drexler schrieb:
> avr-gcc 4.8?
> Darf man den schon richtig benutzen ;-)

Nein, den darf man nicht benutzen!  Außer ich, ich hab eine 
Sondererlaubnis.

Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
> Carl Drexler schrieb:
>> avr-gcc 4.8?
>> Darf man den schon richtig benutzen ;-)
>
> Nein, den darf man nicht benutzen!  Außer ich, ich hab eine
> Sondererlaubnis.

"Mein Name ist Johann. Johann L.
... mit der Lizenz zum compilieren"

Autor: Carl Drexler (Firma: nn) (jcw2)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
meine Frage war durchaus ernst gemeint und bezog sich auf die für mich 
nicht leicht überblickbare Regression-Liste.
Naja, vielleicht nicht "darf man", eher "sollte man".

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Wie gesagt, ich hatte gerade eine 4.8 zur Hand; mit der 4.7 geht das 
bestimmt genauso.

Autor: Coder (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Juhu... die Makro-Funktionen sterben aus und der C Code kann MISRAtener 
werden.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Was ist denn eine Makro-Funktion? Sowas wie eine Header-Bibliothek?

Autor: Detlev T. (detlevt)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Johann L. schrieb:
> Was ist denn eine Makro-Funktion? Sowas wie eine Header-Bibliothek?

So etwas wie
#define SQUARE(x) ((x) * (x))
Also ein Makro mit Parametern. So etwas kann leider böse daneben gehen, 
wenn man z.B. SQUARE(i++) aufruft. Denn es basiert nach wie vor auf 
Textersetzung und expandiert daher zu
((i++) + (i++))

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> So etwas wie

"function-like macro" im englischen (C-)Standard.

Ich glaube "funktionsartiger Makro" wäre eine bessere deutsche
Übersetzung als "Makro-Funktion".  Letzteres würde gemäß den Regeln
der deutschen Sprache eine Funktion implizieren, aber es ist keine
sondern ein Makro.

Autor: Coder (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@Jörg

Ja, das habe ich schlecht "eingedeuscht"; die "function-like macro" 
meinte ich. Funktionartiger Makro klingt gut und besser ist übersetzt 
:-).

Autor: Ferdinand (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> So etwas kann leider böse daneben gehen,
> wenn man z.B. SQUARE(i++) aufruft. Denn es basiert nach wie vor auf
> Textersetzung und expandiert daher zu((i++) + (i++))

Das verstehe ich nicht.
Es müsste doch zu
(i++) * (i++))
expandieren und damit wieder passen?

Beitrag #3028176 wurde vom Autor gelöscht.
Autor: A. K. (prx)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Und was kommt bei i=2 dabei raus?

Autor: Detlev T. (detlevt)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ferdinand schrieb:
> Es müsste doch zu
> (i++) * (i++))
> expandieren und damit wieder passen?

Natürlich "*" statt "+". Da war wohl die Shift-Taste zu langsam...

Das ist aber nicht der Punkt. Die Variable i wird zweimal erhöht anstatt 
einmal, wie SQUARE(i++) suggeriert. Auch dürfte das Ergebnis nicht i*i 
sondern i*(i+1) sein, da die Variable nach Auswertung des ersten 
Ausdruckes bereits erhöht wurde.

AUf jeden Fall dürfte da kaum das heraus kommen, was der Programmierer 
beabsichtigte.

Autor: A. K. (prx)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> Auch dürfte das Ergebnis nicht i*i
> sondern i*(i+1) sein, da die Variable nach Auswertung des ersten
> Ausdruckes bereits erhöht wurde.

Kann sein, muss nicht sein.

Autor: Ferdinand (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Detlev T. schrieb:
> Die Variable i wird zweimal erhöht anstatt
> einmal, wie SQUARE(i++) suggeriert.

Stimmt, jetzt sehe ich es auch.

Autor: Andreas B. (andreasb)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ferdinand schrieb:
> Detlev T. schrieb:
>> Die Variable i wird zweimal erhöht anstatt
>> einmal, wie SQUARE(i++) suggeriert.
>
> Stimmt, jetzt sehe ich es auch.

Ich habs gerate ausprobiert...
#define SQUARE(x) ((x) * (x))

int i = 10;

printf("a = %i\n", i);
printf("b = %i\n", SQUARE(i++));
printf("c = %i\n", i);

./test
a = 10
b = 100
c = 12

;-)

Naja, da hat der Optimizer zugeschlagen?

Ich weiss schon warum ich so Precompiler Makros nicht mag...


mfg Andreas

Autor: A. K. (prx)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Andreas B. schrieb:
> Naja, da hat der Optimizer zugeschlagen?

Das ist eines von 2 zulässigen Resultaten, wobei das auch vom Grad der 
Optimierung und wohl auch der Luftfeuchtigkeit abhängen darf. Es ist 
schlicht offen, wann die Inkrementierungen durchgeführt werden, Pflicht 
ist das erst beim nächsten sequence point.

Autor: Johannes V. (johannes_v)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ich habe vor kurzem angefangen auf meinen ARM's Vererbung und 
Virtualisierung geziehlt einzusetzen. IMHO überwiegen die Vorteile durch 
Lesbarkeit und Produktivitätssteigerung enorm. Ohne groß mit den Flags 
zu spielen macht er bei -o2/3 das alles schon recht gut
  mov r4,  r0
  ldr r3, [r4]
  blx r3

Also idr 2 Befehele mehr, ein paar Tabellen im ROM, welcher eh riesieg 
ist und ein Vptr an der Front der Objekte. Im Hobbybereich kosten die 
Chips auch alle gleichviel und sollte es mal nicht mehr reichen, nehm 
ich halt den nächst Größeren. Das Rummgefummel und der Kampf ums letzte 
bit ist mir die Zeit echt nicht mehr Wert.

Autor: Rolf Magnus (rmagnus)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
A. K. schrieb:
> Andreas B. schrieb:
>> Naja, da hat der Optimizer zugeschlagen?
>
> Das ist eines von 2 zulässigen Resultaten, wobei das auch vom Grad der
> Optimierung und wohl auch der Luftfeuchtigkeit abhängen darf. Es ist
> schlicht offen, wann die Inkrementierungen durchgeführt werden,

Es ist sogar offen, ob sie überhaupt durchgeführt werden und ob danach 
noch irgendwas sinnvolles ausgeführt wird. Nicht nur die Reihenfolge ist 
nicht vorgegeben, sondern das gesamte Verhalten ist laut ISO C (und auch 
C++) undefiniert.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net