Forum: PC-Programmierung Frage zu static-Variable


von Ewald (Gast)


Lesenswert?

Morgen!

Eine Frage zur static-Variable: Ich habe diese deklariert, damit die 
Variable in der Funktion beim nächsten Aufruf auch wieder vorhanden ist 
und ihren Wert nicht verliert.

Wenn ich diese nun aber nicht mehr benötige, wie werde ich sie wieder 
los?

Gibt es einen Befehl, um den Speicher wieder frei zu geben?

: Verschoben durch Admin
von (prx) A. K. (prx)


Lesenswert?

Ewald schrieb:

> Wenn ich diese nun aber nicht mehr benötige, wie werde ich sie
> wieder los?

Überhaupt nicht.

> Gibt es einen Befehl, um den Speicher wieder frei zu geben?

Nein.

von Ewald (Gast)


Lesenswert?

A. K. schrieb:
> Nein.

Wie? Einmal in die elt gesetzt...für immer am Hals? Ist ja schlimmer als 
n Kind.

von (prx) A. K. (prx)


Lesenswert?

Nu - weshalb heisst "static" wohl so? Damit es dynamisch ist?

Beschreib lieber mal das eigentliche Problem als deinen fehlgeschlagenen 
Ansatz zur Lösung. Es gibt nämlich auch statische Zeiger auf dynamischen 
Speicher, wenn's unbedingt sein muss.

von Ewald (Gast)


Lesenswert?

A. K. schrieb:
> Damit es dynamisch ist?

Nee, natürlich nicht, nur kann ja sein, dass man sie explizit wieder 
killen kann, wenn man sie nicht mehr benötigt.

von Ewald (Gast)


Lesenswert?

1
void current_test_out (void)
2
{
3
  static uint8_t position = 5;
4
  
5
  static int8_t  number_1 = 0;
6
  static int8_t  number_2 = 4;
7
  static int8_t  number_3 = 0;
8
  static int8_t  number_4 = 0;
9
  
10
  uint32_t dac_test_value = 0;
11
12
  .....

Das ganze ist in einem Menü. number_1  bis number_4 sind vier Stellen 
auf einem LCD, welche man mit +/- -Tasten einzeln erhöhen, bzw. 
verringern kann.

Da es noch andere Sachen im Programm zu tun gibt, wird das Menü zyklisch 
aufgerufen, die eigentliche Funktion also verlassen.

Wenn ich die Variablen nicht als static deklariere, sind sie natürlich 
beim nächsten Aufruf weg.

Und meine Frage wäre jetzt gewesen, dass wenn ich den Menüpunkt nicht 
mehr aufrufe, die Variable auch weg kann.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Nimm eine globale Variable und nenn sie help. Dann kannst du mit ihr 
machen, was du willst... ;-)

von (prx) A. K. (prx)


Lesenswert?

Du machst dir wegen der paar Bytes solche Sorgen?

von Ewald (Gast)


Lesenswert?

A. K. schrieb:
> Du machst dir wegen der paar Bytes solche Sorgen?

Nein, war ja nur ne Frage, ob es geht.

von Karl H. (kbuchegg)


Lesenswert?

Ewald schrieb:

> Wenn ich die Variablen nicht als static deklariere, sind sie natürlich
> beim nächsten Aufruf weg.

Schon.
Aber warum muss sich diese Funktion die Werte merken?

Warum kann man sich die nicht ausserhalb merken?
Warum müssen das 4 int8_t sein? Warum kann das nicht ein einzelner 
int8_t sein, der von der Funktion bei Betreten (die Funktion bekommt den 
Wert mit) in die einzelnen Stellen zerlegt wird und der von der Funktion 
vor dem Verlassen wieder zu einem int8_t zusammengebaut wird? Die 
Funktion liefert dann an den Aufrufer den neuen, vom Benutzer 
veränderten Wert zurück. Die aufrufende Funktion macht dann mit dem 
Wert, was auch immer notwendig ist und die Funktion muss sich selbst 
intern nichts merken.

Neben dem geringeren Speicherplatzverbrauch gewinnst du dadurch auch 
Flexibilität, da du diese 'Einstellfunktion' dann für viele verschiedene 
Werte in deinem Programm benutzen kannst und nicht nur für einen.


Du versuchst gerade ein 'Problem' zu lösen, dass du bei einem 
vernünftigen Programmdesign gar nicht hättest.

von Ewald (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Warum kann man sich die nicht ausserhalb merken?

Meinst du mit ner globalen Variable?

von Ewald (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> dass du bei einem
> vernünftigen Programmdesign gar nicht hättest

So lang bin ich eben noch nicht beim Programmieren...

von Karl H. (kbuchegg)


Lesenswert?

Ewald schrieb:
> Karl heinz Buchegger schrieb:
>> Warum kann man sich die nicht ausserhalb merken?
>
> Meinst du mit ner globalen Variable?

Kann sein.

Aber:
Warum müssen das 4 int8_t sein? Warum kann das nicht ein einzelner
int8_t sein, der von der Funktion bei Betreten (die Funktion bekommt den
Wert mit) in die einzelnen Stellen zerlegt wird und der von der Funktion
vor dem Verlassen wieder zu einem int8_t zusammengebaut wird? Die
Funktion liefert dann an den Aufrufer den neuen, vom Benutzer
veränderten Wert zurück. Die aufrufende Funktion macht dann mit dem
Wert, was auch immer notwendig ist und die Funktion muss sich selbst
intern nichts merken.

Neben dem geringeren Speicherplatzverbrauch gewinnst du dadurch auch
Flexibilität, da du diese 'Einstellfunktion' dann für viele verschiedene
Werte in deinem Programm benutzen kannst und nicht nur für einen.

von Ewald (Gast)


Lesenswert?

Es ist halt quasi so:
1
main
2
{
3
  irgendwas...
4
  irgendwas anderes...
5
6
  if (menue_soll_angezeigt_werden == JA)
7
  {
8
    switch (menuepunkt)
9
    {
10
      punkt1:
11
      {
12
        ...
13
      }
14
      punktX:
15
      {
16
        static uint8_t position = 5;
17
  
18
        static int8_t  number_1 = 0;
19
        static int8_t  number_2 = 4;
20
        static int8_t  number_3 = 0;
21
        static int8_t  number_4 = 0;
22
  
23
        uint32_t dac_test_value = 0;
24
25
        ...
26
      }
27
    }
28
  }
29
}

von Karl H. (kbuchegg)


Lesenswert?

Ewald schrieb:
> Es ist halt quasi so:

Nicht 'quasi'.

Jeder Fall ist immer ein wenig anders.
Wenn man konkret sagen soll, wie es besser gehen könnte, muss man auch 
den konkreten Code sehen.

von Ewald (Gast)


Lesenswert?

So, das ist das ganze dazu, ist natürlich jetzt recht lang, sind 
eigentlich nur abfragen drin um bestimmte Grenzen nicht zu 
über-/unterschreiten.

4-stellige LCD-Anzeige bei der man mit PLUS und MINUS hoch und runter 
zählen kann und mit einer dritten Taste die Stelle wechselt.

Damit stellt man einen Strom ein, der dann zu einem DAC geschickt wird, 
wenn man die dritte Taste langegedrückt hält.
1
main
2
{
3
  ...
4
  
5
  if ((menu_item == 0) && (get_button_long (BUTTON_3)))
6
  {
7
    menu_item = 1;
8
  }
9
10
  if (menu_item != 0)
11
  {
12
    current_test_out ();
13
  }
14
15
  ...
16
}
17
18
19
20
void current_test_out (void)
21
{
22
  static uint8_t position = 5;
23
  
24
  static int8_t  number_1 = 0;
25
  static int8_t  number_2 = 4;
26
  static int8_t  number_3 = 0;
27
  static int8_t  number_4 = 0;
28
  
29
  uint32_t dac_test_value = 0;
30
  
31
  if (ten_ms_toggle)
32
  {
33
    ten_ms_toggle = FALSE;
34
    
35
    lcd_clear_display ();
36
    lcd_jump_to (2,4);
37
    lcd_send_string ("mA");
38
    lcd_jump_to (1,1);
39
    
40
    switch (position)
41
    {
42
      case 1:
43
      {
44
        if (display_toggle)
45
        {
46
          lcd_send_num (number_1, FALSE);
47
        }
48
        else
49
        {
50
          lcd_send_num (' ', FALSE);
51
        }
52
53
        lcd_send_num (number_2, TRUE);
54
        lcd_send_num (number_3, FALSE);
55
        lcd_send_num (number_4, FALSE);
56
57
        break;
58
      }
59
60
      case 2:
61
      {
62
        lcd_send_num (number_1, FALSE);
63
          
64
        if (display_toggle)
65
        {
66
          lcd_send_num (number_2, TRUE);
67
        }
68
        else
69
        {
70
          lcd_send_num (' ', TRUE);
71
        }
72
73
        lcd_send_num (number_3, FALSE);
74
        lcd_send_num (number_4, FALSE);
75
76
        break;
77
      }
78
79
      case 3:
80
      {
81
        lcd_send_num (number_1, FALSE);
82
        lcd_send_num (number_2, TRUE);
83
          
84
        if (display_toggle)
85
        {
86
          lcd_send_num (number_3, FALSE);
87
        }
88
        else
89
        {
90
          lcd_send_num (' ', FALSE);
91
        }
92
93
        lcd_send_num (number_4, FALSE);
94
95
        break;
96
      }
97
98
      case 4:
99
      {
100
        lcd_send_num (number_1, FALSE);
101
        lcd_send_num (number_2, TRUE);
102
        lcd_send_num (number_3, FALSE);
103
104
        if (display_toggle)
105
        {
106
          lcd_send_num (number_4, FALSE);
107
        }
108
        else
109
        {
110
          lcd_send_num (' ', FALSE);
111
        }          
112
113
        break;
114
      }
115
116
      case 5:
117
      {
118
        lcd_send_num (number_1, FALSE);
119
        lcd_send_num (number_2, TRUE);
120
        lcd_send_num (number_3, FALSE);
121
        lcd_send_num (number_4, FALSE);
122
123
        break;
124
      }
125
    }
126
127
    if (BUTTON_PLUS)
128
    {
129
      switch (position)
130
      {
131
        case 1:
132
        {
133
          number_1 += 1;
134
135
          if (number_1 > 2)
136
          {
137
            number_1 = 0;
138
          }
139
140
          break;
141
        }
142
143
        case 2:
144
        {
145
          number_2 += 1;
146
147
          if (number_1 == 2)
148
          {
149
            if (number_2 > 4)
150
            {
151
              number_2 = 0;
152
            }
153
          }
154
          else if (number_1 == 0)
155
          {
156
            if (number_2 > 9)
157
            {
158
              number_2 = 3;
159
            }
160
          }            
161
          else
162
          {
163
            if (number_2 > 9)
164
            {
165
              number_2 = 0;
166
            }
167
          }
168
169
          break;
170
        }
171
172
        case 3:
173
        {
174
          number_3 += 1;
175
176
          if ((number_1 == 2) && (number_2 == 4))
177
          {
178
            number_3 = 0;
179
          }
180
          else if ((number_1 == 0) && (number_2 == 3))
181
          {
182
            if (number_3 > 9)
183
            {
184
              number_3 = 5;
185
            }
186
          }
187
          else
188
          {
189
            if (number_3 > 9)
190
            {
191
              number_3 = 0;
192
            }
193
          }
194
195
          break;
196
        }
197
198
        case 4:
199
        {
200
          number_4 += 1;
201
202
          if ((number_1 == 2) && (number_2 == 4))
203
          {
204
            number_4 = 0;
205
          }
206
          else
207
          {
208
            if (number_4 > 9)
209
            {
210
              number_4 = 0;
211
            }              
212
          }
213
214
          break;
215
        }
216
      }
217
    }
218
219
    if (BUTTON_MINUS)
220
    {
221
      switch (position)
222
      {
223
        case 1:
224
        {
225
          number_1 -= 1;
226
            
227
          if (number_1 < 0)
228
          {
229
            number_1 = 2;
230
          }
231
232
          break;
233
        }
234
235
        case 2:
236
        {
237
          number_2 -= 1;
238
239
          if (number_1 == 0)
240
          {
241
            if (number_2 < 3)
242
            {
243
              number_2 = 9;
244
            }
245
          }
246
247
          else if (number_1 == 2)
248
          {
249
            if (number_2 < 0)
250
            {
251
              number_2 = 4;
252
            }
253
          }
254
          else
255
          {
256
            if (number_2 < 0)
257
            {
258
              number_2 = 9;
259
            }
260
          }
261
262
          break;
263
        }
264
265
        case 3:
266
        {
267
          number_3 -= 1;
268
269
          if ((number_1 == 2) && (number_2 == 4))
270
          {
271
            number_3 = 0;
272
          }
273
          else if ((number_1 == 0) && (number_2 == 3))
274
          {
275
            if (number_3 < 5)
276
            {
277
              number_3 = 9;
278
            }
279
          }
280
          else          
281
          {
282
            if (number_3 < 0)
283
            {
284
              number_3 = 9;
285
            }
286
          }
287
288
          break;
289
        }
290
291
        case 4:
292
        {
293
          number_4 -= 1;
294
295
          if ((number_1 == 2) && (number_2 == 4))
296
          {
297
            number_4 = 0;
298
          }
299
          else
300
          {
301
            if (number_4 < 0)
302
            {
303
              number_4 = 9;
304
            }
305
          }
306
307
          break;
308
        }
309
      }
310
    }
311
  }
312
313
  if (get_button_short (BUTTON_3))
314
  {
315
    if ((number_1 == 2) && (number_2 >= 4))
316
    {
317
      number_2 = 4;
318
      number_3 = 0;
319
      number_4 = 0;
320
    }
321
    else if ((number_1 == 0) && (number_2 <= 3))
322
    {
323
      number_2 = 3;
324
      number_3 = 5;
325
      number_4 = 0;
326
    }
327
328
    position += 1;
329
330
    if (position > 5)
331
    {
332
      position = 1;
333
    }
334
  }
335
336
  if (get_button_long (BUTTON_3))
337
  {
338
    if ((number_1 == 2) && (number_2 >= 4))
339
    {
340
      number_2 = 4;
341
      number_3 = 0;
342
      number_4 = 0;
343
    }
344
    else if ((number_1 == 0) && (number_2 <= 3))
345
    {
346
      number_2 = 3;
347
      number_3 = 5;
348
      number_4 = 0;
349
    }
350
351
    position = 5;
352
353
    dac_test_value = (number_1 * 1000);
354
    dac_test_value += (number_2 * 100);
355
    dac_test_value += (number_3 * 10);
356
    dac_test_value += number_4;
357
358
    if ((dac_test_value > 2000) || (dac_test_value < 400))
359
    {
360
      dac_test_value = (dac_test_value * 131072);
361
      dac_test_value = (dac_test_value / 3200);
362
      dac_write (dac_test_value, ALARM);
363
    }
364
    else
365
    {
366
      dac_test_value = (dac_test_value - 400);
367
      dac_test_value = (dac_test_value * 65536);
368
      dac_test_value = (dac_test_value / 1600);
369
      dac_write (dac_test_value, NORMAL);
370
    }      
371
  }
372
373
  if (BUTTON_P_M) // Verlassen
374
  {
375
    number_1 = 0;
376
    number_2 = 4;
377
    number_3 = 0;
378
    number_4 = 0;
379
380
    menu_item = 0;
381
  }
382
}

von Karl H. (kbuchegg)


Lesenswert?

Das sieht jetzt für mich erst mal so aus, als ob du den Strom zwischen 0 
und 2500 einstellen können willst.

Melde mich gleich noch mal

von Ewald (Gast)


Lesenswert?

Den Strom kann ich damit zwischen 3,5 und 24mA einstellen.

von Karl H. (kbuchegg)


Lesenswert?

Ein nicht unerklecklicher Teil deiner Funktion beschäftigt sich damit, 
die 4 einzelnen Stellen und deren Zusammenhänge zu 'verwalten'.

Da würde ich einen Ansatzpunkt sehen um den Code zu vereinfachen.
Wenn du grundsätzlich nur einen int16_t hättest, der den momentan 
eingestellten Strom enthält, dann ist ja das Drücken von +/- an den 
einzelnen Position gleichwertig damit, dass dieser Strom um 1; 10; 100; 
1000 erhöht/erniedrigt wird. Damit fällt dir dann aber auch vieles weg, 
was sich jetzt nur um Überträge, Bereichsgrenzen etc. dreht.

Das ist das eine.
Das andere ist: In einem guten Software Design, macht eine Funktion eine 
Aufgabe und nur diese Aufgabe.
Ich würde daher trennen: Die Funktion soll sich um die Benutzereingabe 
kümmern, einen übergebenen Wert entsprechend der Tastendrücke 
manipulieren und als Rückgabewert auch noch mitteilen, ob der Wert jetzt 
zum DAC gegeben werden soll oder nicht.

D.h. nicht die Funktion speicher den aktuellen Wert für current, sondern 
der existiert entweder beim Aufrufer oder überhaupt in einer globalen 
Variablen. Das ebnet dann auch den Weg um zb den Wert im EEPROM 
zwischenzuspeichern (damit er beim Ein/Ausschalten des Geräts wieder 
verfügbar ist) oder eine PC-Schnittstelle über UART nachzurüsten etc.
1
//
2
// wandelt einen Wert in seine ASCII Darstellung
3
// es werden immer 4 Stellen generiert, wobei mit
4
// führenden 0-en aufgefüllt wird.
5
//
6
void my_itoa( int16_t wert, char* buffer )
7
{
8
  //
9
  // das wäre die simpelste Variante
10
  // sprintf( buffer, "%04d", wert );
11
12
  buffer[0] = wert / 1000 + '0';
13
  wert = wert % 1000;
14
  buffer[1] = wert / 100 + '0';
15
  wert = wert % 100;
16
  buffer[2] = wert / 10 + '0';
17
  buffer[3] = wert % 10 + '0';
18
  buffer[4] = '\0';
19
}
20
  
21
//
22
// Die Funktion wendet Tastendrücke auf den übergebenen Wert an
23
//
24
//   '+'     Wert wird erhöht
25
//   '-'     Wert wird erniedrigt
26
//
27
// Rückgabe:
28
//     TRUE     Wert soll an den DAC geschickt werden, Eingabe abgeschlossen
29
//     FALSE    Wert ist manipuliert, Eingabe aber noch nicht abgeschlossen
30
//
31
// Argumente:
32
//     *wert     Zeiger auf eine int16_t Variable, die verändert werden soll
33
//     *digitPos Welche Ziffer ist drann mit editieren
34
//               0 ... Einer
35
//               1 ... Zehner
36
//               2 ... Hunderter
37
//               3 ... Tausender
38
//
39
uint8_t current_test_out( int16_t* wert, uint8_t* digitPos )
40
{
41
  char buffer[5];
42
  int16_t increment[] = { 1, 10, 100, 1000 };
43
44
  if( ten_ms_toggle )
45
  {
46
    ten_ms_toggle = FALSE;
47
    
48
    lcd_clear_display ();
49
    lcd_jump_to (2,4);
50
    lcd_send_string ("mA");
51
    lcd_jump_to (1,1);
52
53
    //
54
    // die Zahl einfach mal mit allen 4 Stellen ausgeben
55
    //
56
    my_itoa( *wert, buffer );
57
    lcd_send_string( buffer );
58
59
    //
60
    // Für das Blinken die richtige Stelle mit einem Leerzeichen
61
    // überschreiben
62
    //
63
    if( toggle_display ) {
64
      lcd_jump_to( 1, 4 - digitPos );
65
      lcd_send_string( " " );
66
    }
67
68
    //
69
    // die Tasten auswerten
70
    //
71
    if( BUTTON_PLUS )
72
      *wert = *wert + increment[digitPos];
73
74
    if( BUTTON_MINUS )
75
      *wert = *wert - increment[digitPos];
76
77
    // sicherstellen, dass der Wert im Rahmen bleibt
78
    // dabei auch Overflows und Underflows handhaben
79
    if( *wert > 3499 )
80
      *wert = 3499
81
82
    if( *wert < 35 )
83
      *wert = 35;
84
85
    //
86
    // wenn jetzt noch die 3.te Taste
87
    //
88
    // Ein kurzer Druck bedeutet: ab zur nächsten Stelle
89
    //
90
    if( get_button_short( BUTTON_3 ) )
91
      *digitPos += 1;
92
      if( *digitPos == 4 )
93
        *digitPos = 0;
94
    }
95
 
96
    //
97
    // ein langer Druck bedeutet:
98
    // Wert am DAC setzen. Das wird einfach dem Aufrufer gemeldet
99
    //
100
    if( get_button_long( BUTTON_3 ) )
101
      return 1;
102
  }
103
104
  return 0;
105
}
106
107
int main()
108
{
109
  int16_t current = 35;
110
  uint8_t digitPos = 0;
111
112
  ...
113
114
115
  while( 1 ) {
116
    ....
117
 
118
119
    if( .....
120
121
      if( current_test_out( &current, &digitPos ) )
122
        set_Current_DAC( current );
123
124
      ...

Warnung: ungetesteter Code

Ob ich mir allerdings den ganzen Teil mit Editierung der Einzelstellen 
antun würde, weiß ich ehrlich gesagt nicht.
Ich hätte mir die PeDa Entprellung genommen und ganz einfach mit dessen 
Autorepeat den Wert einfach um +/- 1 erhöht, bzw. wenn der Autorepeat 
einsetzt, den Wert um +/- 100 erhöht/erniedrigt. Letztendes ist das für 
den Benutzer wahrscheinlich angenehmer, als wie wenn er erst mit einer 
3.ten Taste kompliziert auf die Stelle manövrieren muss, die er braucht 
und die um 1 erhöhen/erniedrigen muss.

von Ewald (Gast)


Lesenswert?

OK, vielen Dank schonmal, das werde ich mir jetzt erstmal zu Gemüte 
führen!

von Vlad T. (vlad_tepesch)


Lesenswert?

was für ein Display benutzt du eigentlich?
der standard text-display-controller (k.A. wie der heißt) hat einen 
einschaltbaren cursor, der blinkt entweder als ganzer Block, oder als 
Unterstrich.
Da braucht man sich nicht selbst um das blinken kümmern

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.