Forum: Compiler & IDEs verwunderter C - Anfänger


von Andreas (Gast)


Lesenswert?

Hallo,
mit Assembler habe ich schon einiges programmiert, nun wollte ich mir 
mal anschauen welche vor und Nachteile C mit sich bringt. Allerdings bin 
ich hier (zu meiner Verwunderung nicht weit gekommen). Hier mal ein 
Beispiel:
1
#include <avr/io.h>
2
#define TAKT 14745600UL
3
 
4
void main (void)
5
{
6
   DDRC  = 255;
7
   PORTC = 0;
8
   
9
 
10
   while(1) 
11
   {
12
   warte16( );
13
   PORTC++;
14
   }
15
}
16
17
void warte16(void)
18
{
19
unsigned long i;
20
for (i = 0; i < 200000; i++);
21
}

dieser kleine Dualzähler funktioniert so wunderbar, wenn ich allerdings 
erst PORTC++; und dann warte16( ); aufrufe, leuchten alle LED´s an Port 
c und es scheint nichts mehr gezählt zu werden.

Solche merkwürdigen Fehler (oder steckt da eine Logik dahinter - ich 
hoffe es) gab es noch einige, wodurch  ich lieber wieder zu Assembler 
zurückkehre, andererseits kann ich mir auch nicht vorstellen, das C so 
voller Probleme steckt, wie es mir im ersten Moment erscheint.

Vielleicht kann mir ja jemand mein obiges Problemchen erläutern, so dass 
ich doch noch Lust auf C bekomme!

Würde mich freuen...

grüße
Andreas

von Andreas K. (a-k)


Lesenswert?


von Andreas (Gast)


Lesenswert?

aber warum macht es einen unterschied, ob ich warten16(); vor oder nach 
dem setzen vom PORT aufrufe????

von Simon K. (simon) Benutzerseite


Lesenswert?

Andreas wrote:
> aber warum macht es einen unterschied, ob ich warten16(); vor oder nach
> dem setzen vom PORT aufrufe????

Vermutlich schlägt dir der Optimizer ein Schnippchen! Versuche (wie 
schon erwähnt) die integrierten _delay_xy Funktionen zu benutzen. 
(Obiger Link)

PS: Vergiss aber nicht F_CPU mit anzugeben. (Bei AVR-Studio geht das in 
den Project Settings. Wo du hoffentlich auch den richtigen AVR-Typen 
eingetragen hast. Ohne AVR Studio benutzt du einfach ein Define an 
oberster Stelle)

von Christian R. (supachris)


Lesenswert?

Mit volatile vor der Deklaration Zählvariable wird wohl dann auch 
klappen.

von Simon K. (simon) Benutzerseite


Lesenswert?

Christian R. wrote:
> Mit volatile vor der Deklaration Zählvariable wird wohl dann auch
> klappen.

Volatile hat da nix zu suchen. Oder wird dann die for-schleife nicht 
wegoptimiert?

von Werner B. (Gast)


Lesenswert?

> ...Oder wird dann die for-schleife nicht wegoptimiert?

So isses

von Simon K. (simon) Benutzerseite


Lesenswert?

Gut, dann nehme ich sofort alles zurück und behaupte das Gegenteil! ;)

von Stefan Salewski (Gast)


Lesenswert?

Das habe ich jetzt nicht ganz verstanden?
Die Warteschleife des urspünglichen Posters wird anfangs brav 
ausgeführt, und wenn der die Reihenfolge der zwei Anweisungen 
vertauscht, wird die Warteschleife total wegoptimiert? Das wäre doch 
wirklich seltsam. (Ich kanns derzeit nicht testen, ich habe derzeit nur 
avr-gcc 3.4.6, da bleiben Warteschleifen erhalten.)

von Xenu (Gast)


Lesenswert?

@ Stefan Salewski

Ich habe mir mal den generierten Assemblercode angeschaut.

Dieses Verhalten hat wohl was mit dem Funktions-Inlining zu tun.
So wie es ausschaut ist Inlining wohl standardmäßig eingeschaltet.

Also schaut der Code mit "warte16()" vor "PORTC++" quasi so aus:
1
  unsigned long i;
2
  for (i = 0; i < 200000; i++);
3
  PORTC++;

Und offenbar ist es so, das der gcc diese an sich nutzlose Schleife 
nicht wegoptimiert (wie er es eigentlich sollte, wenn i nicht als 
volatile deklariert ist). Wenn man sie hinter "PORTC++" schreibt macht 
er das nämlich schon.

Wenn man bei warte16() das inlining abschaltet, wird sie in beiden 
Fällen (vor/hinter PORTC++) tatsächlich auch aufgerufen, besteht aber 
nur aus "ret".

Also immer volatile bei Warteschleifen benutzen oder gleich die 
mitgelieferten Delayfunktionen benutzen.

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.