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
unsignedintF2=0;
2
3
unsignedintstepsX=59;
4
unsignedintstepsY=42;
5
6
intmain(){
7
8
F2=stepsX/stepsY;
9
10
return0;
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
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
unsignedintF2=0;
ein
1
volatileunsignedintF2=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.)
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
Hi!
Also ch hab das mal mit "volatile" ausprobiert, das brachte keine
Änderung. nunhab ich den Code mal so geschrieben:
1
volatileunsignedintF2;
2
3
voidhorst(){
4
unsignedintstepsX=59;
5
unsignedintstepsY=42;
6
7
F2=stepsX/stepsY;
8
}
9
10
intmain(){
11
12
horst();
13
14
while(1){
15
if(!F2)break;
16
}
17
18
return0;
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
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
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
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.
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
unsignedintF2;
2
unsignedintstepsX=21;
3
unsignedintstepsY=4;
4
5
intmain(){
6
7
F2=stepsX%4;
8
9
10
return0;
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
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.
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, ...
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
intdevide(intd,intc){
2
returnd/c;
3
}
Devide.h
1
intdevide(intd,intc){
2
returnd/c;
3
}
eigentliches Programm
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include"Devide.c"
4
5
unsignedintF2;
6
unsignedintstepsX=21;
7
unsignedintstepsY=4;
8
9
intmain(){
10
11
F2=devide(stepsX,stepsY);
12
13
return0;
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
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.
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