Division mit GCC (AVR Studio)

#1818325
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
#1818350
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.)
Gast #1818356
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
#1818367
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
#1818433
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
#1818449
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.
#1818474
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
#1818490
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, ...
#1818517
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren