Forum: Compiler & IDEs Division mit GCC (AVR Studio)


von Manuel S. (injen)


Lesenswert?

Hi!

Ich lese schon eine ganze Weile hier mit und bin eigentlich immer 
schnell zum Ziel gekommen mit den hier vorhandenen Artikeln. Allerdings 
sitze is seit heute früh vor einem Programm für einen Atmel und 
irgendwie raubt mir AVR Studio den letzten Nerv.

Es ist eigentlich ganz simpel: Ich will 2 Zahlen (unsigned int) 
dividieren. Der Rest bzw die Nachkommastelle interessiert erstmal nicht.
Nun hab ich schon rausgefunden, dass es keine Hardwaredivision gibt - 
ist ja auch nicht wild. Trotzdem funktioniert die Geschichte nicht, wenn 
ich es in C einfach so reinschreibe. Hier erstmal der Code:
1
unsigned int F2 = 0;
2
3
unsigned int stepsX = 59;
4
unsigned int stepsY = 42;
5
6
int main() {
7
8
F2 = stepsX/stepsY;
9
10
return 0;
11
}

Eigentlich nicht schwer. Wenn ich diesen Code nun kompiliere und 
ausführe (Optimierung ist aus), dann geht er an die Zeile mit F2... und 
wenn ich diese dann ausführen will mit F11, überspringt er sowohl die 
Berechnung, als auch das "return 0;" und alle Variablen sind Plötzlich 
"Not in Scope". Ich verstehe das Absolut nicht, zumal dieser Fehler auch 
auftritt, wenn ich statt der Division eine Modulo Operation machen will. 
Ist genau das Gleiche in grün, auch mit "unsigned char" geht es nicht. 
Sobald ich eine Variable in die Berechnung eintrage ist Schicht.
1
F2 = 7/3;

das Funktioniert ohne Probleme, aber wahrscheinlich nur weil das bereits 
vom Compiler ausgerechnet wird.


Ich hoffe Jemand kann mir helfen...das Problem ist echt komisch. 
Übrigens funktioniert dieser oben stehende Code ohne Probleme, wenn ich 
ihn als "normales" C-Programm in Dev-C schreibe und ausführe.

Gruß
Manuel

von Hc Z. (mizch)


Lesenswert?

Manuel Spehr schrieb:
> dann geht er an die Zeile mit F2... und
> wenn ich diese dann ausführen will mit F11, überspringt er sowohl die
> Berechnung, als auch das "return 0;" und alle Variablen sind Plötzlich
> "Not in Scope".

Der Grund dafür ist, dass der Compiler die Zeile wegoptimiert hat.  Da 
weder die Division noch ihr Resultat irgendwo verwendet werden, darf er 
das.  Um dem Compiler klar zu machen, dass die Variable F2 eine Rolle 
spielt, die er nicht überblicken kann, und auf jeden Fall zu ermitteln 
ist, musst Du aus
1
unsigned int F2 = 0;
ein
1
volatile unsigned int F2 = 0;
machen.

Möglicherweise musst Du das mit beiden Operanden der Division auch 
machen, damit der Compiler keine vorberechnete Zahl reinschreibt.

(Das =0 kannst Du übrigens weglassen.  Es ist unnötig und globale 
Variablen werden ohnehin mit 0 initialisiert.)

von AVR (Gast)


Lesenswert?

Hc Zimmerer schrieb:
> Der Grund dafür ist, dass der Compiler die Zeile wegoptimiert hat.

Manuel Spehr schrieb:
> Wenn ich diesen Code nun kompiliere und
> ausführe (Optimierung ist aus)

Das ist nicht der Grund. Aber bei globalen Variablen hab ich beim 
simulieren auch das Problem. Es wird aber im AVR definitiv 
funktionieren. Wenn du das simulieren möchtest, dann nimm lokale 
Variablen oder kopier die globalen zum Testen in lokale innerhalb der 
Funktion

von Manuel S. (injen)


Lesenswert?

Hi!

Also ch hab das mal mit "volatile" ausprobiert, das brachte keine 
Änderung. nunhab ich den Code mal so geschrieben:
1
volatile unsigned int F2;
2
3
void horst() {
4
unsigned int stepsX = 59;
5
unsigned int stepsY = 42;
6
7
F2 = stepsX/stepsY;
8
}
9
10
int main() {
11
12
horst();
13
14
while(1) {
15
if(!F2) break;
16
}
17
18
return 0;
19
}

Dabei wären die Variablen ja lokal und F2 nicht unnütz, jedenfalls 
sollte der Compiler nicht glauben dass F2 nicht benutzt wird.

Jedenfalls macht er hier auch nichts anderes. Sobald er an die Stelle 
für die Berechnung von F2 kommt überspringt er alls und ist plötzlich am 
Ende der main().

Kann man diesen Optimierungsblödsinn nicht irgendwie generell 
deinstallieren !? Ich benutze das sowieso nie.

Gruß Manuel

von AVR (Gast)


Lesenswert?

Manuel Spehr schrieb:
> Dabei wären die Variablen ja lokal

F2 ist aber nicht lokal.
Nimm eine lokale Variable zum testen:
1
void horst() {
2
  unsigned int stepsX = 59;
3
  unsigned int stepsY = 42;
4
  unsigned int tmp = 42;
5
6
  tmp = stepsX/stepsY;
7
  F2 = tmp;
8
}

von Manuel S. (injen)


Lesenswert?

Auch hier - keine Änderung.
Passiert auch das Gleiche, wenn ich F2 ganz rausnehme und global 
garnicht mehr benutze. Sprich wenn alles lokal ist.

Zwischendrin erstmal Danke für die Hilfe.

Gruß Manuel

von Markus J. (markusj)


Lesenswert?

Manuel Spehr schrieb:
> Kann man diesen Optimierungsblödsinn nicht irgendwie generell
> deinstallieren !? Ich benutze das sowieso nie.

Das willst du nicht wirklich, weil genau das mit ein Grund ist, warum du 
GCC benutzt und nicht BASCOM Basic programmierst.
Der "Optimierungsblödsinn" macht dir ein korrektes Programm 
(normalerweise, sonst ist es ein Compilerbug ...) nicht kaputt.
Wenn etwas mit Optimierung nicht korrekt funktioniert hast du entweder 
vergessen, dem Compiler wichtige Informationen mitzuteilen (volatile 
etc.) oder der Compiler hat ein Schlupfloch im C-Standard gefunden dass 
bestimmte Annahmen zur Optimierung erlaubt ("Signed Integer laufen nicht 
über" hust). In beiden Fällen liegt der schwarze Peter letztendlich 
bei dir, der Compiler hält sich nur an das Regelwerk ...

Und normalerweise hat man die Optimierung immer eingeschaltet, weil sie 
die Programmgröße deutlich reduziert und das Endprodukt deutlich 
beschleunigen kann.

mfG
Markus

von (prx) A. K. (prx)


Lesenswert?

Manuel Spehr schrieb:

> Kann man diesen Optimierungsblödsinn nicht irgendwie generell
> deinstallieren !? Ich benutze das sowieso nie.

Du solltst statt dessen versuchen, sinnvollen Testcode zu schreiben. Es 
ist die Aufgabe des Compilers, den schnellsten oder kürzesten Code zu 
erzeugen. Wenn du ihm die Chance gibst, Divisionen zur Übersetzungszeit 
durchzuführen, dann wird er das Angebot u.U. annehmen.

Vogehensweise bei solchem Testcode: Dem Compiler die Information nehmen, 
die er für die Optimierung benötigt. Hier beispielsweise: Diese Funktion 
getrennt von der Initialisierung der verwendeten Variablen und vom 
Aufruf übersetzen. Dann sind auch keine Hacks mit volatile nötig.

Und zu volatile: Wenn nicht nur F2 sondern auch die stepsX/Y volatile 
sind, dann darf er den Zugriff darauf wie auch die Division nicht 
weglassen. Ist jedoch nur F2 volatile, dann wird dort ein vorberechneter 
Wert reingeschreben, wenn der Compiler weiss, dass die ursprünglichen 
Werte in den stepsX/Y noch drinstehen.

Mit -O0 lässt sich die Optimierung aber durchaus abschalten. Für 
Debugging mitunter nützlich, weil der Debugger sonst Probleme haben 
kann, Code und Quelltext korrekt in Verbindung zu bringen und u.U. recht 
seltsam herumhüpft. Das gilt insbesondere für -O2 aufwärts, z.T. auch 
für -Os, weshalb bei Single-Step Debugging jedenfalls nicht mehr als -O1 
verwendet werden sollte.

von Manuel S. (injen)


Lesenswert?

Hi!

A. K. schrieb:
> Hier beispielsweise: Diese Funktion
> getrennt von der Initialisierung der verwendeten Variablen und vom
> Aufruf übersetzen. Dann sind auch keine Hacks mit volatile nötig.

Irgendwie kann ich dir da nicht ganz folgen. Dann müsste ich doch die 
Dateien auseinanderfummeln und dann die Datei mit der Funkion einbinden 
!?

Abgesehen davon ist ja die Optimierung schön und gut, und dass der Code 
bisher unsinnig ist, ist mir auch logisch aber das ändert ja nichts 
daran, dass wenn ich im -O0 arbeite er den Code garnicht optimieren 
sollte. Trotzdem bricht er die Sache aber ab, sobald dort Variablen 
auftauchen.

Ich bin nochmal ne Stufe runtergegangen. Wie schon gesagt passiert das 
gleiche mit der Modulo Operation.
1
unsigned int F2;
2
unsigned int stepsX = 21;
3
unsigned int stepsY = 4;
4
5
int main() {
6
7
F2 = stepsX%4;
8
9
10
return 0;
11
}

Dieser Code z.b. Funktioniert und rechnet mir F2 = 1 aus. Das kann ich 
auch normal Schritt für Schritt verfolgen, aber sobald ich statt "...%4" 
eben "...%stepsY" schreibe, bricht er wieder dort ab. Wohlbemerkt alles 
mit -O0 also keiner Optimierung.

Gruß Manuel

von (prx) A. K. (prx)


Lesenswert?

Manuel Spehr schrieb:

> Irgendwie kann ich dir da nicht ganz folgen. Dann müsste ich doch die
> Dateien auseinanderfummeln und dann die Datei mit der Funkion einbinden
> !?

Ich weiss nicht, inwieweit du mit dem Konzept getrennter Übersetzung von 
getrennten Quellcodefiles mit abschliessendem Verlinken vertraut bist.

von Manuel S. (injen)


Lesenswert?

Leider garnicht, aber ich kann ja mal bissn googeln und gucken wie es 
geht...

Gruß Manuel

von (prx) A. K. (prx)


Lesenswert?

Ich habe die Version von 13:58 mal mit dem avr-gcc überprüft, den ich 
hier rumliegen habe (4.3.4, nicht produktiv), mit -O0. Mit Variable wird 
per Laufzeitfunktion dividiert, mit Konstante wird %4 durch das 
gleichwertige aber viel schnellere &3 ersetzt.

Beides ist korrekt und ist auch jeweils eine Laufzeitberechnung, aber 
sehr verschieden ausgeführt. Wie sich das im Debugger darstellt habe ich 
nicht kontrolliert.

Wenn er beim Aufruf der Laufzeitfunktion abbricht, ohne die aber nicht, 
dann hast du möglicherweise ein ganz anderes Problem, z.B. einen falsch 
platzierten Stack, für einen falschen Controller übersetzten Code, ...

von Manuel S. (injen)


Lesenswert?

Hi!

Bin gerade bei der Geschichte mit getrenntem Quellcode. Funktionier 
tnoch nicht ganz...

Zu dem Stack: Den legt doch eigentlich AVR Studio fest !? Dort ist ein 
ATmega16 eingestellt. Ich schreibe das Programm ja auch noch nicht auf 
einen µC, teste halt nur mit dem Simulator rum. Übrigens funktionieren 
andere Laufzeitfunkionen wie z.b. Addition oder Multiplikation.


EDIT:
auch wenn es danach
Beitrag "Quellcode aufteilen in C"
sog "Bullshit" ist, hab ich nun folgendes gemacht:

Devide.c
1
int devide(int d, int c) {
2
return d/c;
3
}

Devide.h
1
int devide(int d, int c) {
2
return d/c;
3
}

eigentliches Programm
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include "Devide.c"
4
5
unsigned int F2;
6
unsigned int stepsX = 21;
7
unsigned int stepsY = 4;
8
9
int main() {
10
11
F2 = devide(stepsX, stepsY);
12
13
return 0;
14
}

Er öffnet nun beim der Simulation die eingebundene Datei und rechnet 
auch wie es scheint. Sobald er allerdings zurückkommt kommt wieder der 
Abbruch.
Hab irgendwie nicht das Gefühl, dass das wa sich da veranstaltet habe 
vernünftig ist.

Gruß Manuel

von (prx) A. K. (prx)


Lesenswert?

Manuel Spehr schrieb:

Devide.h
1
int devide(int d, int c);

NB: Es heisst auch im Englischen "division", nicht "devision".

> eigentliches Programm
1
#include "Devide.h"

von (prx) A. K. (prx)


Lesenswert?

Manuel Spehr schrieb:

> auch wie es scheint. Sobald er allerdings zurückkommt kommt wieder der
> Abbruch.

Was heisst "Abbruch"? Knall, Peng, der Rechner platzt?

Und was erwartest du am Ende von main(). Freundliche weibliche Stimme, 
die sich von dir verabschiedet? Bei Controllern gibt es im Grunde kein 
Programmende.

von Manuel S. (injen)


Lesenswert?

Hi!

Nein, ich erwarte, dass er das zurückgegebene Ergebnis von divide() in 
F2 reinschreibt und das passiert nicht.

edit: mit Abbruch meine ich, dass plötzlich das Programm am Ende ist, 
ohne die Zuweisung auf F2 oder das "return 0;" von der main()

Gruß Manuel

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.