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 ;-)
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.
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.
"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.
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.
Im gegebenen Beispiel ist xMessage statisch. Also erst einmal kein Problem.
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?
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.