Notes d'étude sur l'architecture ARM et le langage C (Wei Dongshan) (3) - quelques questions sur les variables locales, les variables globales, la pile et le tas


1. Quand utiliser des variables globales et des variables statiques

Les variables globales conviennent aux situations où les données doivent être partagées entre plusieurs fonctions ou modules . Lors de la définition d'une variable globale, des facteurs tels que la convention de dénomination de la variable, la portée et le type de stockage doivent être pris en compte pour garantir l'exactitude et la lisibilité de la variable.

Les variables statiques conviennent aux situations où la persistance des données entre les appels de fonction est requise . La portée des variables statiques est le fichier entier, peut être utilisée dans n'importe quelle fonction du fichier et ne sera initialisée qu'une seule fois pendant l'exécution du programme, elle peut donc être utilisée pour stocker certaines données qui doivent conserver l'état.

Pour les occasions multi-processus, il ne convient pas aux variables globales. La sécurité des processus signifie que dans un environnement multi-processus, plusieurs processus peuvent accéder à la même ressource en même temps sans problèmes tels que des conditions de concurrence. Dans la programmation multi-processus, puisque chaque processus a un espace d'adressage indépendant, les variables globales ne sont pas partagées entre les différents processus, c'est-à-dire que chaque processus aura sa propre copie de la variable globale.
Cela conduit à un problème : si plusieurs processus accèdent à la même variable globale en même temps, chaque processus exploitera sa propre copie, ce qui peut entraîner une incohérence des données, des conditions de concurrence, etc., puis affecter l'exactitude et la stabilité du programme. Par conséquent, l'utilisation de variables globales pour la communication inter-processus et les données partagées n'est pas fiable. Afin de résoudre ce problème, certains mécanismes de communication inter-processus peuvent être utilisés, tels que les pipelines, les files d'attente de messages, la mémoire partagée, etc., pour réaliser le partage et la communication de données inter-processus.

Deuxièmement, pourquoi les variables locales doivent-elles parfois être statiques ? Après avoir ajouté statique, la variable n'est-elle plus dans la pile ?

int add_val(volatile int v){
    
    
    static volatile int a=321;
    v=v+a;
    return v;
}

(1) Cette variable locale a est modifiée par static. Lorsque nous avons besoin de conserver la valeur de la variable locale entre les appels de fonction, ou de partager des données entre différentes fonctions , nous pouvons utiliser le mot-clé static pour déclarer la variable locale statique. Une variable locale statique définie à l'intérieur d'une fonction ne terminera pas son cycle de vie lorsque la fonction est appelée, mais existera toujours pendant l'exécution du programme. Sa portée est toujours à l'intérieur de la fonction, mais comme son cycle de vie est plus long que celui des variables locales ordinaires, il peut conserver sa valeur inchangée entre plusieurs appels de fonction . De plus, l'initialisation des variables locales statiques ne sera effectuée que lorsque la fonction est appelée pour la première fois, et les appels suivants n'effectueront plus d'opérations d'initialisation, de sorte qu'elle peut être utilisée pour stocker certaines données qui doivent conserver l'état.
(2) Les variables locales statiques sont stockées dans la zone de données statiques, pas sur la pile . La zone de données statiques fait partie du programme et est utilisée pour stocker des données telles que des variables globales, des variables statiques et des constantes statiques. Son cycle de vie est le même que le cycle d'exécution du programme, donc des variables locales statiques existent toujours pendant l'exécution du programme.

3. La proportion d'espace de code compilé par KEIL

insérez la description de l'image ici
Cette information est l'information de taille du programme, qui comprend les quatre parties suivantes, et l'unité est l'octet :

Code : la taille du segment de code, qui fait référence à la partie de code exécutable du programme, y compris les fonctions, les instructions, etc. Dans cet exemple, la taille du segment de code est 30646.

Données RO : taille du segment de données en lecture seule, qui fait référence à des données telles que des variables et des constantes en lecture seule dans le programme. Dans cet exemple, la taille du segment de données en lecture seule est 2806.

RW-data : La taille du segment de données de lecture et d'écriture, qui fait référence aux variables et données lisibles et inscriptibles dans le programme. Dans cet exemple, la taille du segment de données de lecture et d'écriture est de 2 736.

Données ZI : La taille du segment de données non initialisées, qui fait référence aux variables et données lisibles et inscriptibles non initialisées dans le programme. Dans cet exemple, la taille du segment de données non initialisé est 2240.

4. Une récursivité trop profonde entraînera-t-elle un débordement de pile ?

Une récursivité trop profonde peut provoquer un débordement de pile . Une fonction récursive stockera les informations d'appel de la fonction actuelle dans la pile chaque fois qu'elle est appelée. Lorsqu'il y a trop de récursivités, l'espace de la pile peut être épuisé, ce qui entraîne un débordement de la pile. Dans la plupart des langages de programmation, la taille de l'espace de la pile est limitée, généralement entre quelques Mo et des dizaines de Mo. Si le nombre d'appels de fonction récursifs dépasse la taille de l'espace de pile, cela provoquera un débordement de pile. Un débordement de pile peut provoquer des pannes de programme ou un comportement imprévisible.

5. Que sont le segment de code et le segment de données dans FLASH ?

Dans les systèmes embarqués, les programmes sont généralement stockés dans une mémoire flash (Flash). Dans la mémoire flash, un programme est généralement divisé en un segment de code et un segment de données.
Le segment de code est une zone où les instructions du programme sont stockées et est généralement en lecture seule . Les instructions stockées dans le segment de code sont le code du programme traduit en code machine par le compilateur, et elles sont exécutées par le processeur lors de l'exécution du programme.
Le segment de données est la zone de stockage des données statiques et des variables globales avec des valeurs initiales dans le programme . Les segments de données sont généralement divisés en segments de données en lecture seule et en segments de données lisibles et inscriptibles. Le segment de données en lecture seule comprend généralement des données non modifiables telles que des constantes et des chaînes de caractères dans le programme ; le segment de données lisibles et inscriptibles comprend généralement des données lisibles et inscriptibles telles que des variables globales et des variables statiques dans le programme.
Pendant l'exécution du programme, le code du programme et les segments de données sont chargés dans la RAM. Le code de programme est chargé dans la mémoire d'instructions et le segment de données est chargé dans la mémoire de données. Lors de l'exécution du programme, l'interaction entre la mémoire d'instructions et la mémoire de données ainsi que la lecture et l'écriture de données dans la mémoire sont toutes contrôlées par le processeur.

6. Le segment de code et le segment de données dans FLASH peuvent-ils être copiés dans la RAM ?

Oui, le segment de code et le segment de données du programme peuvent être copiés dans la RAM. Ce processus est souvent appelé « duplication de code » ou « initialisation des données » .

Le but de la duplication de code est généralement d'améliorer l'efficacité d'exécution du programme. En raison de la vitesse de lecture lente de la mémoire flash, une fois le segment de code du programme copié dans la RAM, l'instruction peut être directement lue à partir de la RAM lorsque le programme est exécuté, ce qui réduit le nombre de fois pour lire les instructions à partir du mémoire flash, améliorant ainsi les performances du programme Efficacité d'exécution .
Le but de l'initialisation des données est d'attribuer des valeurs initiales aux données statiques et aux variables globales au démarrage du programme. Étant donné que les données stockées dans la mémoire flash sont en lecture seule, elles ne peuvent pas être modifiées pendant l'exécution du programme. Afin de pouvoir modifier ces données, ces données doivent d'abord être copiées dans la RAM. Lors du processus de copie des données, vous pouvez attribuer des valeurs initiales à ces données pour répondre aux besoins du programme.

Sept, tandis que (1) et pour (;;)

while(1) et for(;;) sont les deux instructions utilisées pour représenter une boucle infinie.
while(1) signifie que lorsque la condition entre parenthèses est vraie, l'instruction dans la boucle sera exécutée tout le temps, car 1 est une valeur vraie, donc cette boucle continuera à s'exécuter jusqu'à ce que le programme soit terminé de force.
for(;;) signifie qu'il n'y a pas de condition de boucle, et cette boucle continuera à s'exécuter jusqu'à ce que le programme soit terminé de force. Sa structure en boucle est équivalente à while(1), mais la syntaxe est légèrement plus concise.

Huit, #define pi 3.14 et statique flaot pi=3.14

#define pi 3.14 est une directive de préprocesseur qui remplace toutes les occurrences de pi dans le programme avant la compilation, en la remplaçant par 3.14. Le pi ainsi défini est une constante dont la valeur est déterminée lors de la compilation, sa valeur ne peut donc pas être modifiée lors de l'exécution du programme. L'avantage de cette méthode de définition est qu'elle est simple et facile à comprendre, mais l'inconvénient est qu'elle ne prend pas en charge la vérification de type et qu'elle est sujette à des opérations erronées entre différents types de données. Par exemple, s'il existe une fonction dont le paramètre doit être une valeur de type float, mais qu'un pi est passé lorsque la fonction est appelée, une erreur d'incompatibilité de type se produira.

static float pi=3.14 est la définition d'une variable statique, qui définit une variable statique nommée pi et l'initialise à 3.14. L'avantage de cette définition est qu'elle peut prendre en charge la vérification de type, et la valeur de cette variable peut être modifiée pendant l'exécution du programme. La portée d'une variable statique est limitée à la fonction ou au fichier qui la définit, de sorte que différentes fonctions ou fichiers peuvent définir des variables statiques portant le même nom sans s'affecter mutuellement. L'inconvénient de cette définition est qu'elle nécessite d'occuper de l'espace mémoire, car l'espace mémoire des variables statiques est alloué lors de l'exécution du programme et existe jusqu'à la fin du programme.

9. Chaque tâche de RTOS est-elle équivalente à une fonction ? La pile sera-t-elle libérée ?

Dans RTOS, chaque tâche peut être considérée comme une fonction indépendante, qui a son propre point d'entrée et son propre contexte d'exécution, et peut être exécutée et gérée indépendamment. Chaque tâche a son propre espace de pile pour stocker des informations telles que les variables locales et les piles d'appels de fonction .

Lorsqu'une tâche est créée, le RTOS lui alloue un espace de pile pour stocker des informations telles que des variables locales et des piles d'appels de fonction . Lorsque l'exécution de la tâche est terminée, l'espace de la pile sera libéré pour être utilisé par d'autres tâches. Par conséquent, chaque tâche a sa propre pile indépendante et il n'y aura pas de problèmes tels que la confusion des piles.

Lorsqu'une tâche est suspendue, le RTOS enregistre l'espace de pile de la tâche dans la mémoire, de sorte que l'espace de pile puisse continuer à être utilisé lors de la prochaine reprise de l'exécution. Lorsqu'une tâche est supprimée, le RTOS libère l'espace de pile de la tâche pour une utilisation par d'autres tâches.

Dix, à ajouter...

Je suppose que tu aimes

Origine blog.csdn.net/qq_53092944/article/details/131105248
conseillé
Classement