Forum: Compiler & IDEs Frage zu Code


von Waldemar T. (sanchez251)


Lesenswert?

Hallo All!

Wahrscheinlich ein Anfängerproblem... Folgendes:

Habe zwei Variablen, die ich ich in meinem Hauptprogramm miteinander 
verarbeten will. Die eine ist global als volatile deklariert:

volatile uint16_t iGuthaben = 0;

Die andere im Hauptprogramm Lokal als flaot:

float fTemp2 = 0;

Im Hauptprogramm bezieht sich folgender Code auf die Variablen:

fTemp2 = (iGuthaben/3600);

Wenn ich diese Zeile lösche ist mein Speicher zu etwa 16% belegt 
(Optimierung 0s), wenn ich die Zeile drin hab ist der Speicher zu ca. 
61% belegt!!! Wieso?

Danke und Gruß
Waldemar

von Marcus K. (marcusk)


Lesenswert?

weil eine Division auf in Software gemachert werden muss und dabei auch 
etwas code benötigt. Divisionen sollte man vermeiden und erst recht mit 
float.

Wir vermuten mal alles das es um ein Atmel geht, richtig?

von Waldemar T. (sanchez251)


Lesenswert?

Ja, richtig... ATMega8...

Es liegt nicht an der Division...

Wenn ich den Gode so schreibe:

fTemp2 = iGuthaben;
cStunden = fTemp2/3600;

und dann die obere Zeige weglösche und kompiliere geht die Auslastung 
von 60,4% --> 18,3%. Es muss irgendwie an der zwischen einer Volatile 
und einer float liegen oder so...

von Marcus K. (marcusk)


Lesenswert?

> Es liegt nicht an der Division...
> Wenn ich den Gode so schreibe:
> fTemp2 = iGuthaben;
> cStunden = fTemp2/3600;

wenn der compiler gut optimiert, dann macht er keine Division mehr.

von Waldemar T. (sanchez251)


Lesenswert?

Was willst du damit sagen?

von Marcus K. (marcusk)


Lesenswert?

> Was willst du damit sagen?
das man an den bisschen code sehr wenig ablesen kann, wenn der compiler 
feststellt das die Division eh nur mit Konstanten ausgeführt wird, dann 
passiert es schnell mal das er die division komplett weglässt.

von Waldemar T. (sanchez251)


Lesenswert?

Aha... Wenn ich das richtig sehe, sind die beiden keine Konstanten... 
Außerdem funktioniert die division (zumindest teils, aber das ist eine 
andere Sache).

Das ist aber keine Antwort auf meine Frage... Ich wollte vorest mal nur 
wissen, wieso ich plötzlich so viel code habe???

von yalu (Gast)


Lesenswert?

Im ersten Beispiel wird eine Integer-Division und eine Konvertierung von
Integer nach Float gemacht. Letztere braucht besonders viel Flash-
Speicher, weil du beim Linken das -lm weggelassen hast.

Im zweiten Beispiel wird nur eine Integer-Float-Konvertierung gemacht,
da du cStunden im weiteren Verlauf des Programm nicht mehr benutzt, so
dass die Division wegoptimiert wird.

Löscht du die Zeile

  fTemp2 = iGuthaben;

bleibt von den beiden Zeilen gar nichts mehr übrig, deswegen wird das
Programm deutlich kürzer.

von Marcus K. (marcusk)


Lesenswert?

dann schau ins map file oder die asm datei. Vergleiche die Dateien mit 
und ohne dem volatile.

von Waldemar T. (sanchez251)


Lesenswert?

Ok ich hol mal ein bisschen weiter aus...

Das Programm dient dazu eine 16Bit-Zahl (Sekunden) in Stunden und 
Minuten umzurechnn um dann den Wert auf einem Display auszugeben (in dem 
Fall als Timer-Funktion)

Hier der Relevante Teil des Codes:
1
// Variablendefinitionen Global
2
volatile uint16_t millisekunden = 0;
3
volatile uint16_t iGuthaben = 3670;
4
5
.
6
.
7
.
8
9
// Variable Headerdateien
10
#include <subs/interrupt.c> // Alle Interruptroutinen
11
12
.
13
.
14
.
15
16
// Programmstart
17
int main ()
18
 
19
{
20
//----------------------------------------------------------------------
21
// Variablendefinitionen lokal
22
  char cBuffer[20];
23
  float fTemp2 = 0;
24
  uint16_t temp1 = 0;
25
  uint8_t cSekunden = 0;
26
  uint8_t cMinuten = 0;
27
  uint8_t cStunden = 0;
28
29
.
30
.
31
.
32
33
// main loop
34
35
  do
36
  {
37
38
.
39
.
40
.
41
42
    temp1++;
43
44
    if (temp1 == 0x0FFF)
45
    {
46
    temp1 = 0;
47
48
    fTemp2 = iGuthaben;
49
    cStunden = fTemp2/3600;
50
    cMinuten = (fTemp2-(3600*cStunden))/60;
51
    cSekunden = (fTemp2-(60*cMinuten))/60;
52
                lcd_clear();
53
          _lcd_string("Zeit = ");
54
55
          itoa(cStunden, cBuffer, 10);
56
          _lcd_string(cBuffer);
57
58
    _lcd_data(58);              // 58 = :
59
60
    itoa(cMinuten, cBuffer, 10);
61
          _lcd_string(cBuffer);
62
63
    _lcd_data(58);              // 58 = :  
64
65
    itoa(cSekunden, cBuffer, 10);
66
          _lcd_string(cBuffer);
67
68
          _lcd_string("s");
69
70
71
    }
72
73
  }
74
}

Im Timer2 werden die Millisekunden gezählt, und bei Tausend wird von 
iGuthaben halt eins abgezählt. So sollte es eigentlich funktionieren... 
Ich hoffe der Code ist nicht zu lang um ihn hier reinzuschreiben...

gruß
Waldemar

von Marcus K. (marcusk)


Lesenswert?

habe jetzt hier keine Möglichkeit zu testen aber ich versteht nicht 
warum du überhaupt float verwendest?

Versuche es mal ohne float,

auch geht soetwas bestimmt etwas schöner
>(fTemp2-(3600*cStunden))/60;

schau dir mal das %(modulo) an.

von Waldemar T. (sanchez251)


Lesenswert?

mhh, ja, kann sein... Für vorschläge bin ich gerne offen! Allerdings 
liegt es ja nicht an der Division!

Habs ausprobiert... Wenn ich diese Zeile auser Kraft setze schrumpft mir 
mein Code auf 16% Auslastung!!!
1
    fTemp2 = iGuthaben;           //Auslastung = 61%
2
3
//  fTemp2 = iGuthaben;           //Auslastung = 16%

... Bin ratlos ...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Waldemar T. schrieb:
> mhh, ja, kann sein... Für vorschläge bin ich gerne offen! Allerdings
> liegt es ja nicht an der Division!

Es gibt eine int->float Konvertierung. Das geht nicht in Hardware 
sondern in Software und braucht eben Platz.

Übrigens ist float hier Overkill, das geht alles mit int-Arithmetik. 
float ist bequem, aber eben auch platzfressend...

von yalu (Gast)


Lesenswert?

> Wenn ich diese Zeile auser Kraft setze schrumpft mir mein Code auf 16%
> Auslastung!!!

Klar, dann ist nämlich fTemp2=0. Das weiß auch der Compiler, berechnet
die Ausdrücke in den folgenden drei Zeilen selbst und lässt nur noch
folgendes stehen:
1
    cStunden = 0;
2
    cMinuten = 0;
3
    cSekunden = 0;

Das braucht nicht viel Speicher :)

von yalu (Gast)


Lesenswert?

So geht's übrigens ohne Float und ohne Temporärvariable:
1
    cStunden  = iGuthaben / 3600;
2
    cMinuten  = iGuthaben / 60 % 60;
3
    cSekunden = iGuthaben % 60;

von Waldemar T. (sanchez251)


Lesenswert?

Hey, es geht! :) Ohne Platzfressen! :))

Könntest du mir bitte erklären, was der code macht, oder wo ich das 
nachlesen könnte (war mir bisher nicht bekannt...)

von Waldemar T. (sanchez251)


Lesenswert?

yalu schrieb:

> Klar, dann ist nämlich fTemp2=0. Das weiß auch der Compiler, berechnet
> die Ausdrücke in den folgenden drei Zeilen selbst und lässt nur noch
> folgendes stehen:

> cStunden = 0;
> cMinuten = 0;
> cSekunden = 0;

> Das braucht nicht viel Speicher :)

Johann L. schrieb:

> Es gibt eine int->float Konvertierung. Das geht nicht in Hardware
> sondern in Software und braucht eben Platz.


Jetzt versteh ich das ganze auch... Wusste nicht, wie der Compiler das 
handhabt...

Habe früher in Assembler programmiert, da wurde eben befehl für befehl 
abgearbeitet... ;)

Gruß waldemar

von Falk B. (falk)


Lesenswert?


von yalu (Gast)


Lesenswert?

> Könntest du mir bitte erklären, was der code macht, oder wo ich das
> nachlesen könnte (war mir bisher nicht bekannt...)

iGuthaben ist die Zeit in Sekunden, also z.B. 10000.

Eine Stunde hat 3600 Sekunden, also muss iGuthaben durch 3600
dividiert werden, um die Anzahl der Stunden zu erhalten:
1
    cStunden  = iGuthaben / 3600;

Da sowohl iGuthaben als auch 3600 Integer-Werte sind, wird auch die
Division in Integer durchgeführt und damit die Nachkommestellen
abgeschnitten, was in diesem Fall auch erwünscht ist. Im Beispiel ist
das Ergebnis 10000/3600=2.

Entsprechend ergibt iGuthaben / 60 die Anzahl der Minuten, im Beispiel
also 10000/60=166. Davon müssen aber noch die 2 Stunden (=120 Minuten)
von oben abgezogen werden, so dass 46 Minuten übrig bleiben. Statt von
den 166 Minuten die 120 Minuten abzuziehen, kann man auch die Modulo-
funktion (%-Operator in C) verwenden: 166%60 berechnet den Rest der
Division von 166 durch 60, was ebenfalls 46 ergibt. Das führt dann zu
dem zweiten Ausdruck:
1
    cMinuten  = iGuthaben / 60 % 60;

Die übrigen Sekunden, die noch nicht in den berechneten Stunden und
Minuten berücksichtigt sind, ergeben sich aus dem Rest der Division der
Gesamtsekundenanzahl durch 60, im Beispiel also 10000%60=40:
1
    cSekunden = iGuthaben % 60;

Also sind 10000 Sekunden = 2 Stunden 46 Minuten und 40 Sekunden.

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.