Forum: Compiler & IDEs Code in Funktion zusammenfassen


von Sven (Gast)


Lesenswert?

Hallo,

ich habe in meiner main Funktion mehrere Ereignis, die mehere lokale 
Variablen der Funktion main zurücksetzen sollen.

Bsp.
1
int main(void){
2
uint8_t Ereignis1
3
uint8_t Ereignis2
4
uint8_t Ereignis3
5
uint8_t Variable1
6
uint8_t Variable2
7
uint8_t Variable3
8
uint8_t Variable4
9
uint8_t Variable5
10
11
  while(1){
12
    if (Ereignis1){
13
      Variable1=0;
14
      Variable2=0;
15
      Variable3=0;
16
      Variable4=0;
17
      Variable5=0;
18
    }
19
20
    if (Ereignis2){
21
      Variable1=0;
22
      Variable2=0;
23
      Variable3=0;
24
      Variable4=0;
25
      Variable5=0;
26
    }
27
28
    if (Ereignis3){
29
      Variable1=0;
30
      Variable2=0;
31
      Variable3=0;
32
      Variable4=0;
33
      Variable5=0;
34
    }
35
  }
36
}

Nun hätte ich aber gerne eine Funktion geschrieben, die einfach 
aufgerufen wird und alle 5 Variablen zurückgesetzt werden (aufgrund 
Übersichtlichkeit und Schreibarbeit).
Die Funktion sähe dann z.B. so aus:
1
void Ruecksetzen (void){
2
  Variable1=0;
3
  Variable2=0;
4
  Variable3=0;
5
  Variable4=0;
6
  Variable5=0;
7
  
8
  return;
9
}

Nun ist ja aber das Problem, dass die Funktion die Variablen aus main 
nicht kennt.
Wir kann man so etwas lösen ohne die Variablen global anzulegen? Geht 
das überhaupt?

von egal (Gast)


Lesenswert?

Was du brauchst sind Pointer.

von Jörg E. (jackfritt)


Lesenswert?


von Peter D. (peda)


Lesenswert?

Eine allgemeine Lösung gibt es nicht.
Wenn die Variablen irgendwas miteinander zu tun haben, legt man sie 
besser als Array oder Struct an. Zum Löschen kann man dann memset() 
benutzen.
1
memset( my_array, 0, sizeof(my_array));

Gegen global spricht eigentlich nichts, es sein denn, sie solllen 
schnell sein (in Registern).

Man kann auch den Code so umstellen, daß die gleiche Sache nur an einer 
Stelle auftritt:
1
int main(void){
2
uint8_t Ereignis1
3
uint8_t Ereignis2
4
uint8_t Ereignis3
5
uint8_t Variable1
6
uint8_t Variable2
7
uint8_t Variable3
8
uint8_t Variable4
9
uint8_t Variable5
10
11
  while(1){
12
    Variable1=0;
13
    Variable2=0;
14
    Variable3=0;
15
    Variable4=0;
16
    Variable5=0;
17
    while(1){
18
     if (Ereignis1)
19
       break;
20
     if (Ereignis2)
21
       break;
22
     if (Ereignis3)
23
       break;
24
     if (Ereignis4)
25
       break;
26
    }
27
  }
28
}

Peter

von Karl H. (kbuchegg)


Lesenswert?

Sven schrieb:

> Wir kann man so etwas lösen ohne die Variablen global anzulegen? Geht
> das überhaupt?


Du brauchst sehr dringend ein C-Buch.
Argument Passing an Funktionen und alles was damit zusammenhängt ist 
eine grundlegende Basistechnik in der Programmierung.

1
void foo( int* i)
2
{
3
  *i = 5;
4
}
5
6
int main()
7
{
8
  int j = 8;
9
10
  // j hat den Wert 8
11
12
  foo( &j );
13
14
  // jetzt hat j den Wert 5. foo hat ihn gesetzt
15
}

von Peter II (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Argument Passing an Funktionen ist eine grundlegende Basistechnik.

das ist zwar richtig, aber für 5 Variablen würde ich das nicht als 
sinnvoll ansehen. Hier ist wirklich die einfachste Lösung die Variablen 
global zu machen.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz Buchegger schrieb:
>> Argument Passing an Funktionen ist eine grundlegende Basistechnik.
>
> das ist zwar richtig, aber für 5 Variablen würde ich das nicht als
> sinnvoll ansehen.

Nächste Basistechnik:
Die Variablen haben ja meistens einen sinnvollen Bezug zueinander. Da 
stülpt man dann eine struct drüber.

von Fabian O. (xfr)


Lesenswert?

Variablen, die man dauerhaft braucht, lokal in der main-Funktion 
anzulegen macht ohnehin nicht viel Sinn. Damit verschleiert man nur den 
Speicherverbrauch und erschwert sich, wie man sieht, das Programmieren.

Mach die Variablen modul-global, wenn mehrere Funktionen darauf 
zugreifen sollen:
1
static uint8_t Ereignis1;
2
static uint8_t Ereignis2;
3
static uint8_t Ereignis3;
4
static uint8_t Variable1;
5
static uint8_t Variable2;
6
static uint8_t Variable3;
7
static uint8_t Variable4;
8
static uint8_t Variable5;
9
10
static void reset_vars(void)
11
{
12
  Variable1 = 0;
13
  Variable2 = 0;
14
  Variable3 = 0;
15
  Variable4 = 0;
16
  Variable5 = 0;
17
}
18
19
int main(void)
20
{
21
  while(1) {
22
    if (Ereignis1) {
23
      reset_vars();
24
    }
25
    if (Ereignis2) {
26
      reset_vars();
27
    }
28
    if (Ereignis3) {
29
      reset_vars();
30
    }
31
  }
32
}

Wenn es mehrere gleichartige Variablen sind bietet es sich übrigens an, 
daraus ein Struct oder Array zu machen statt alle einzeln anzulegen. 
Aber der Code ist ja nur ein Beispiel.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Fabian O. schrieb:
> int main(void)
> {
>   while(1) {
>     if (Ereignis1) {
>       reset_vars();
>     }
>     if (Ereignis2) {
>       reset_vars();
>     }
>     if (Ereignis3) {
>       reset_vars();
>     }
>   }
> }

Warum kein logisches OR verwenden?

von Progger (Gast)


Lesenswert?

Peter II schrieb:
> das ist zwar richtig, aber für 5 Variablen würde ich das nicht als
> sinnvoll ansehen. Hier ist wirklich die einfachste Lösung die Variablen
> global zu machen.

Die "einfachste" Lösung ist es schon, aber sicher nicht die Beste. 
Globale Variable soll man nicht verwenden. Die bringen ordentlich 
Probleme mit sich. Für "quick'n'dirty" können sie ab und zu ganz 
praktisch sein. Aber warum soll man sich in diesem Fall den Klotz 
"globale Variable" an das Bein binden, wenn es doch auch einfach 
ordentlich geht?

von Peter II (Gast)


Lesenswert?

Progger schrieb:
> Aber warum soll man sich in diesem Fall den Klotz
> "globale Variable" an das Bein binden, wenn es doch auch einfach
> ordentlich geht?

der übergeben von Variabeln kosten auch zeit (bei einem kleinen AVR 
durch aus relevent). Außerdem sieht so so gleich den RAM verbraucht. 
Damm muss man sich auch noch um das init kümmern, das braucht man bei 
globalen auch nicht.

auf einem PC verwende ich auch keine Globalen variablen, auf einem AVR 
schon.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:

> der übergeben von Variabeln kosten auch zeit (bei einem kleinen AVR
> durch aus relevent).

Es kommt immer drauf an, wieviele Argumente man hat, welche Datentypen 
involviert sind, wie oft die Funktion aufgerufen wird, wie zeitkritisch 
das ganze ist, ....

> auf einem PC verwende ich auch keine Globalen variablen, auf einem AVR
> schon.

Yep. Auf einem AVR muss man schon mal die Krot aus praktischen Gründen 
schlucken.
Nichtsdestotrotz MUSS der TO lernen, wie Argument Passing funktioniert. 
Denn für alles und jedes globale Variablen zu machen, ist dann ebenfalls 
der falsche Ansatz
1
void puts()
2
{
3
  while( global_arg_to_puts )
4
  {
5
    global_arg_to_putc = *s++;
6
    putc();
7
  }
8
}
9
10
11
int main()
12
{
13
  ....
14
15
  global_arg_to_puts = "Hallo world";
16
  puts();
17
18
  global_arg_to_puts = "Juhu";
19
  puts();
20
21
  sprintf( buffer, "%d", i );
22
  global_arg_to_puts = buffer;
23
  puts();

das kanns ja offensichtlich nicht sein.

von jack (Gast)


Lesenswert?

ich würd jetzt gerne einen blöden Kommentar schreiben, von wegen C-Buch 
und Stringzuweisung, aber ich weiß ja was du mit dem Beispiel sagen 
willst :-)

von Fabian O. (xfr)


Lesenswert?

jack schrieb:
> ich würd jetzt gerne einen blöden Kommentar schreiben, von wegen C-Buch
> und Stringzuweisung

Die "Stringzuweisung" wäre in Ordnung, sofern global_arg_to_puts als 
char* definiert ist. Die puts-Funktion würde allerdings nicht 
funktionieren ... ;-)

Man sollte übrigens deutlich zwischen globalen Variablen (ohne static) 
und Modulvariablen (mit static) unterscheiden. Letztere sind kein 
Teufelszeug und wird man in jedem realen, vernünftig geschriebenen 
C-Programm brauchen, egal ob µC oder PC.

von Peter II (Gast)


Lesenswert?

Fabian O. schrieb:
> Letztere sind kein
> Teufelszeug und wird man in jedem realen, vernünftig geschriebenen
> C-Programm brauchen, egal ob µC oder PC.

doch sind sie, spätestens wenn man mit Threads anfängt merkt man das 
globale (egal welche) nicht wirklich gut sind.

von Fabian O. (xfr)


Lesenswert?

Wo speicherst Du denn stattdessen die Daten?

von Peter II (Gast)


Lesenswert?

Fabian O. schrieb:
> Wo speicherst Du denn stattdessen die Daten?

was für daten? z.b. in stucts.


struct Moduldaten md;
ModulInit( &md );

ModulMachWas( &md, "was soll ich machen?" );

ModulClose( &md );

von Fabian O. (xfr)


Lesenswert?

1
struct Moduldaten md;
ist doch eine globale Variable? Oder legst Du die in der main-Funktion 
auf dem Stack an? Oder mit malloc? Wenn ja, was soll daran besser sein?

von Peter II (Gast)


Lesenswert?

Fabian O. schrieb:
> Oder legst Du die in der main-Funktion
ja

> auf dem Stack an? Oder mit malloc?
ist egal

> Wenn ja, was soll daran besser sein?
ich kann das Modul mehrfach gleichzeig z.b. in Thread nutzen.

von jack (Gast)


Lesenswert?

Also praktisch "pseudo-objektorientiert", fehlen nur noch 
Funktionszeiger in der Struktur :-)

Aber reden wir hier von PC oder uC?

von Fabian O. (xfr)


Lesenswert?

Peter II schrieb:
> ich kann das Modul mehrfach gleichzeig z.b. in Thread nutzen.

Das hat ja nichts damit zu tun, wo Du die Variable anlegst. Du machst 
also folgendes:
1
int main(void)
2
{
3
  struct Moduldaten md;
4
5
  ModulInit( &md );
6
  ModulMachWas( &md, "was soll ich machen?" );
7
  ModulClose( &md );
8
}

Mein Frage ist, warum nicht so?
1
static struct Moduldaten md;
2
3
int main(void)
4
{
5
  ModulInit( &md );
6
  ModulMachWas( &md, "was soll ich machen?" );
7
  ModulClose( &md );
8
}

Vorteil:
- Der Compiler kann den Speicherverbrauch ermitteln.
- Die Daten belegen keinen Platz auf dem Stack (gerade am PC relevant, 
wenn die Struktur groß ist und der Stack begrenzt).
- Du kannst ModulMachWas() auch von anderen Funktionen in main.c aus 
aufrufen, ohne dass der Funktion &md übergeben werden muss (darum ging 
es ja im Prinzip im Ausgangspost).

Nachteil:
- Mir fällt keiner ein?

von Peter II (Gast)


Lesenswert?

Fabian O. schrieb:
> Nachteil:
> - Mir fällt keiner ein?

so wie du es jetzt gemacht hast es es ja ok, wenn aber das

static struct Moduldaten md;

in der Modul.c datei steht, dann wird es blöd.

von Fabian O. (xfr)


Lesenswert?

Das ist ein anderes Thema, nämlich ob man von dem Modul mehrere 
Instanzen braucht oder nicht. Wenn man garantiert nur eine Instanz davon 
hat/braucht, dann kann man sich das Übergeben des Zeigers auf die Daten 
bei jedem Funktionsaufruf sparen. Bei Mikrocontrollern ist das meiner 
Erfahrung nach meistens der Fall ...

In Anwendungen, bei denen man mit mehreren Modulen mit mehrfachen 
Instanzen zu tun hat, fährt man wahrscheinlich mit C++ besser, denn da 
ist die Objektorientierung gleich eingebaut.

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.