Speicherherkunft für Variable

Gast #239060
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 ;-)
Gast #239061
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.
Gast #239062
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.
Gast #239063
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.
Gast #239064
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.
Gast #239066
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?
Gast #239067
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.
Gast #239068
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

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.