www.mikrocontroller.net

Forum: Compiler & IDEs Speicherherkunft für Variable


Autor: Heiko Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ich hab eine Verständnisfrage zur Speicherbelegung von Funktionen in
C:

gegeben sei folgende Funktion:

void test (void) {
    char c;
    <do something>
}

Meines Wissens nach kommt der Speicherplatz für "char c" vom Stack
und könnte so nach Beenden der Funktion wieder gelöscht werden. Ich
denke, daß muss so sein weil ja z.B. sich die Funktion rekursiv
aufrufen könnte und der Compiler ja nicht wissen kann wieviele
Speicherstellen er nun reservieren muss. Stimmt das so?

Falls ja hab ich noch ne Frage ;-)

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Normalerweise hast Du recht. Nur ausgerechnet bei hiesigen Thema, bei
Mikrocontrollern, gilt das nicht immer.

Prozessoren wie 8051 und PIC tun sich arg schwer mit Adressierung von
Daten auf dem Stack, weshalb da recht oft auch lokale Daten statisch
abgelegt werden. Ist dann wählbar, pro Funktion oder global. Natürlich
sind solche Funktionen dann weder rekursiv verwendbar, noch sollte man
sie in sowohl in Interrupts als auch im Hauptprogramm verwenden.

Autor: Heiko Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok danke. was passiert dann bei folgendem Konstrukt:

char * globalpointer;

void test (void) {
    char c = 'x';
    globalpointer = &c;
}

Nehme ich richtig an, daß nachdem "test" beendet wurde ich mich nicht
mehr in anderen Funktionen darauf verlassen kann, daß ich nach
Dereferenzierung von globalpointer wieder mein 'x' erhalte? Denn
nachdem die Funktion beendet wurde müsste der Speicher ja wieder
freigegeben worden sein.


Konkret beschäftige ich mich nämlich derzeit mit FreeRTOS und da gibts
dieses Beispiel hier:

 // Task to create a queue and post a value.

 void vATask( void *pvParameters )

 {

 struct AMessage *pxMessage;



    // Create a queue capable of containing 10 pointers to AMessage
structures.

    // These should be passed by pointer as they contain a lot of
data.

    xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );

    if( xQueue == 0 )

    {

        // Failed to create the queue.

    }



    // ...



    // Send a pointer to a struct AMessage object.  Don't block if
the

    // queue is already full.

    pxMessage = & xMessage;

    xQueueSend( xQueue, ( void * ) &pxMessage, ( portTickType ) 0 );



  // ... Rest of task code.

 }

Es wird eine Queue erstellt, die Pointer auf AMessage-structs
speichert. Aber was bringt mir das, wenn z.B. die Funktion in der die
Message erzeugt wurde zurückkehrt und damit quasi irgendwas an der
Stelle stehen kann, wo der Pointer der Message hinzeigt.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Nehme ich richtig an, daß nachdem "test" beendet wurde ich mich
nicht
mehr in anderen Funktionen darauf verlassen kann, daß ich nach
Dereferenzierung von globalpointer wieder mein 'x' erhalte?"

Korrekt.

Zu dem FreeRTOS Beispiel: xQueueSend kopiert die Bytes sofort von der
angegebenen Adresse in den Message-Puffer. Kopiert hier also den Inhalt
des Pointers pxMessage. Solange xMessage selbst nicht auf dem Stack
steht, ist das ok.

Autor: Heiko Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also müsste ich den Speicher für xMessage mit malloc o.ä. reservieren
(FreeRTOS bietet ja diese Möglichkeit)?
Gibt es noch eine andere Möglichkeit? Einfach "struct AMessage
xMessage;" innerhalb von vATask kann ja nicht die Lösung sein, da es
dann auf dem Stack stehen würde.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Im gegebenen Beispiel ist xMessage statisch. Also erst einmal kein
Problem.

Autor: Heiko Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm wo? ich sehe da gar keine Deklaration von xMessage. Okay sie ist
nicht am Anfang von "vATask" so dass sie ausserhalb sein muss.

Aber dann  gäbe es doch auch nur eine einzige Instanz von diesem struct
und maximal 10 Pointer auf das selbe struct in der Queue speichern zu
können macht doch auch keinen Sinn. Oder?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nu, in genau dem Beispiel, das Du oben zitierst, ist xMessage statisch
(genauer: external scope) definiert:

struct AMessage
 {
    portCHAR ucMessageID;
    portCHAR ucData[ 20 ];
 } xMessage;

Aber dass man das nicht mehrfach gleichzeitig senden kann, ist schon
klar. Nur sind Beispiele für APIs nicht dazu da, dem Leser das
Mitdenken ganz zu ersparen ;-).

Generell ist allerdings malloc/free in embedded system nicht
unproblematisch. Allokation ist noch ok, anfangs jedenfalls, aber
besser ist es, wenn man ohne wiederholte allokation/deallokation
auskommt. Sofern man auf Zuverlässigkeit Wert legt.

Autor: Heiko Otto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du siehst ja, ich versuche mitzudenken :-)

Ich suche halt nur eine Möglichkeit das Beispiel sinnvoll zu verwenden.
Ich meine damit, wenn ich mir irgendwo eh 10 verschiedene AMessages
(z.B. external scope in einem Array) deklarieren muss (damit den
Speicher fest reserviere), damit ich auch 10 verschiedene Pointer auf
die Queue legen kann, dann kann ich doch auch die Queue so
initialisieren, daß sie direkt 10 AMessages speichern kann und nicht
nur die Pointer auf diese.

Es sei denn ich reserviere den Speicherbereich für die AMessages eben
zur Laufzeit. Nur dann macht das meiner Meinung nach Sinn die Queue für
Pointer zu initialisieren.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.