Forum: Compiler & IDEs Speicherherkunft für Variable


von Heiko Otto (Gast)


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 ;-)

von A.K. (Gast)


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.

von Heiko Otto (Gast)


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.

von A.K. (Gast)


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.

von Heiko Otto (Gast)


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.

von A.K. (Gast)


Lesenswert?

Im gegebenen Beispiel ist xMessage statisch. Also erst einmal kein
Problem.

von Heiko Otto (Gast)


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?

von A.K. (Gast)


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.

von Heiko Otto (Gast)


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.

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.