Sur l'efficacité d'exécution du code en langage C

L'efficacité d'exécution dont nous parlons habituellement est la surcharge système générée en utilisant le même algorithme pour effectuer le même calcul dans les mêmes conditions d'entrée. Actuellement, nous prêtons généralement plus d'attention à la surcharge du temps d'exécution. Le code écrit dans toutes les langues finira par s'exécuter et devra être converti en code machine. Il est plus efficace d'accomplir la même chose en moins de temps.

Parlons de la façon d'améliorer l'efficacité d'exécution du programme en langage C.

1. Essayez d'éviter d'appeler des fonctions de retard

 

Un programme sans système d'exploitation ne peut être exécuté que de manière cyclique en tant que (1). Si vous y appelez beaucoup de retard, il consommera des ressources CPU. Le retard équivaut à le laisser reposer ici, seulement interrompu Seul l'intérieur sera exécuté. Si vous faites juste un programme que la LED clignote une fois par seconde, c'est très simple, vous pouvez appeler directement la fonction de retard, mais dans les projets réels, il y a souvent beaucoup de choses à faire dans la grande boucle, pas pour les occasions avec des exigences en temps réel élevées Trop.

 

Afin d'éviter l'utilisation du retard, vous pouvez utiliser l'interruption de la minuterie pour générer un bit indicateur. Lorsque le bit indicateur temporel est défini, vous n'avez qu'à détecter le bit indicateur dans le programme principal, le configurer pour qu'il s'exécute une fois, puis effacer l'indicateur. Je ferai d'autres choses à d'autres moments au lieu d'attendre ici. Le meilleur exemple est l'affichage du tube nixie, qui utilise l'affichage de la tonalité d'interruption. Ensuite, il y a la détection de clé. La procédure générale consiste à faire pendant que (! Clé) attend que la clé soit relâchée. Si la touche est maintenue enfoncée, le programme suivant ne s'exécutera jamais et mourra ici. En fait, vous pouvez faire un logo de clé pour détecter la goutte Le bord et les bords ascendants peuvent éviter ce problème.

2. Le code doit être aussi concis que possible pour éviter les doublons

 

J'ai vu la partie du code affichée sur le tube numérique écrite dans le livre qui a appris le MCU en 10 jours, sélectionné un peu, puis envoyé les données, puis sélectionné un peu, puis envoyé les données et terminé à son tour. Le taux de répétition du code est trop élevé, ce qui non seulement occupe trop de mémoire de classe, mais a également une faible efficacité d'exécution et une mauvaise lisibilité. Il n'implémente que la fonction. La programmation réelle peut être une boucle, pour une boucle ou une boucle while. Un tel code semble plus de niveau.

3. Utilisation raisonnable des définitions de macro

 

Si une variable ou un registre est fréquemment utilisé dans le programme, vous pouvez utiliser la définition de macro pour définir un nouveau nom à la place. Cet avantage est pratique pour la modification. Par exemple, P1 connecté au bus de terminal de données de l'écran LCD. Maintenant, vous voulez passer à P0, il vous suffit de modifier la définition de macro ici. Lorsque le compilateur compile, il remplacera automatiquement le nom défini par le nom réel Le nom.

4. Utilisez le type de données le plus petit possible

 

Par exemple, la plage de valeurs d'une variable est comprise entre 0 et 255, puis elle est définie comme unsignedchar, bien sûr, elle peut également être définie comme unsignedint, mais cela entraîne un gaspillage de mémoire et l'efficacité de l'opération est inférieure.

 

Si les données n'ont pas de nombre négatif, essayez de le définir comme un type non signé. Vous devez éviter d'être défini comme un type de données à virgule flottante ou un type à double précision (8 octets). Ces deux types consomment beaucoup de ressources CPU lors du calcul.

 

Par exemple, la plage de tension de collecte est de 0 à 5 V, avec une précision de trois décimales, vous pouvez étendre les données collectées de 1000 fois, même si le maximum n'est que de 5000, puis collecter plusieurs fois pour créer un algorithme de filtrage, et enfin avoir seulement besoin de calculer la tension Il suffit d'ajouter un point décimal après le premier chiffre et la variable est définie comme une variable non signée.

5. Évitez d'utiliser la multiplication et la division

 

La multiplication et la division consomment des ressources CPU. En regardant le code d'assemblage, vous constaterez qu'une opération de multiplication et de division compilera 10 voire des dizaines de lignes de code. S'il est multiplié ou divisé par 2 à la nième puissance, il peut être implémenté avec << ou >>. Cette opération de décalage est déjà calculée au moment de la compilation, donc le code est très concis et l'efficacité de fonctionnement est élevée. Mais vous devez porter une attention particulière à la priorité des opérateurs.

 

6. Essayez d'utiliser des opérateurs d'affectation composés

 

Quelle est la différence entre les deux expressions a = a + b et a + = b?

 

La première consiste à calculer d'abord la valeur de a + b, puis à l'enregistrer dans le registre ACC, puis à affecter la valeur du registre ACC à a. Ce dernier attribue directement la valeur de a + b à a, économisant une étape. Bien qu'une seule instruction soit enregistrée, qu'en est-il lorsque cette opération se répète des milliers et des dizaines de milliers de fois? L'effet est alors évident.

 

Comme les autres- =, * =, / =,% =, etc. sont les mêmes.

7. Essayez de ne pas définir de variables globales

 

Examinez d'abord les similitudes et les différences entre les variables locales, les variables globales, les variables locales statiques et les variables globales statiques.

 

▶ Variables locales:

Les variables définies dans une fonction ou une instruction composée sont des unités de stockage allouées dans la zone de stockage dynamique, allouées dynamiquement lors de l'appel et automatiquement libérées lorsque la fonction ou l'instruction composée se termine.

 

▶ Variables locales statiques:

Lorsqu'une variable locale est définie dans une fonction, si la déclaration statique est ajoutée, la variable est une variable locale statique et l'unité de stockage est allouée dans la zone de stockage statique et n'est pas libérée pendant l'exécution du programme; les variables locales statiques ne peuvent être utilisées que dans la fonction; Les variables locales statiques sont affectées au moment de la compilation (si aucune affectation n'est effectuée au moment de la définition, l'affectation par défaut est 0 (pour les variables numériques) ou caractères nuls (pour les variables de caractères)); les variables locales statiques ne sont pas automatiquement libérées après la fin de l'appel de fonction , Conservez la valeur une fois l'appel de fonction terminé.

 

▶ Variables globales:

Les variables définies en dehors de la fonction sont appelées variables globales. Les variables globales sont allouées aux unités de stockage dans la zone de stockage statique et ne sont pas libérées pendant le fonctionnement du programme. Les fonctions du fichier peuvent appeler la variable globale et les fonctions des autres fichiers la variable globale. Besoin d'ajouter une instruction externe.

 

▶ Variables globales statiques:

Lorsqu'une variable est définie en dehors de la fonction, si l'instruction staTIc est ajoutée, la variable est une variable globale statique; la variable globale statique est allouée à une unité de stockage dans la zone de stockage statique et n'est pas libérée pendant l'exécution du programme. La variable globale statique est affectée au moment de la compilation (si Si aucun traitement d'affectation n'est effectué pendant la définition, la valeur d'affectation par défaut est 0 (pour les variables numériques) ou caractères nuls (pour les variables de caractères); elle ne peut être utilisée que dans le fichier actuel.

 

▶ Résumé:

Dans des circonstances normales, il est défini comme une variable locale, qui non seulement fonctionne plus efficacement, mais est également facile à transplanter. Les variables locales sont principalement situées dans des registres à l'intérieur du MCU. Dans la plupart des MCU, la vitesse de fonctionnement de l'utilisation des registres est plus rapide que le stockage de données, et les instructions sont de plus en plus flexibles, ce qui est propice à la génération de code de meilleure qualité, et les registres occupés par des variables locales Et le stockage des données peut être réutilisé dans différents modules.

 

Lorsque vous devez utiliser des variables dans une interruption, vous devez les définir en tant que variables globales et ajouter du volume pour empêcher l'optimisation du compilateur. Si les données sont en lecture seule, comme le code cassé du tube numérique, la bibliothèque de polices modulo de caractères chinois doit être placée dans la ROM, afin que la RAM puisse être sauvegardée, le 51 monopuce est ajouté avec le code et le monopuce plus avancé est ajouté avec la modification const.

8. Choisissez le bon algorithme et la bonne structure de données

 

Vous devez être familier avec le langage des algorithmes et connaître les avantages et les inconvénients de divers algorithmes.Pour des informations spécifiques, veuillez vous référer aux documents de référence correspondants, qui sont introduits dans de nombreux livres informatiques. Le remplacement de la méthode de recherche séquentielle plus lente par une méthode de recherche binaire ou de recherche dans le désordre plus rapide, et l'insertion ou le tri à bulles avec un tri rapide, un tri par fusion ou un tri racine peuvent améliorer considérablement l'efficacité de l'exécution du programme. Il est également important de choisir une structure de données appropriée. Un pointeur est une variable contenant une adresse, et la variable pointée par lui peut être adressée. L'utilisation d'un pointeur peut facilement passer d'une variable à la suivante, il est donc particulièrement adapté au fonctionnement d'un grand nombre de variables. Les tableaux et les instructions de pointeur ont une relation très étroite. En règle générale, les pointeurs sont plus flexibles et concis, tandis que les tableaux sont plus intuitifs et faciles à comprendre. Pour la plupart des compilateurs, l'utilisation de pointeurs est plus courte que le code généré à l'aide de tableaux et l'efficacité d'exécution est plus élevée. Dans Keil, en revanche, le code généré à l'aide d'un tableau est plus court que le pointeur utilisé.

9. Utiliser la compilation conditionnelle

 

En général, lors de la compilation d'un programme en langage C, tous les programmes participent à la compilation, mais on espère parfois qu'une partie du contenu ne sera compilée que lorsque certaines conditions sont remplies. Il s'agit d'une compilation conditionnelle. La compilation conditionnelle peut choisir différentes étendues de compilation en fonction de la situation réelle, générant ainsi des codes différents.

 

10. Intégrer la traduction de compilation-killer

 

Le langage d'assemblage est le langage informatique le plus efficace. Dans le développement de projet général, le langage C est généralement utilisé pour le développement, car l'intégration de l'assembly affectera la portabilité et la lisibilité de la plate-forme, et les instructions d'assemblage des différentes plates-formes sont incompatibles. Mais pour certains programmeurs persistants qui ont besoin du programme pour obtenir l'efficacité ultime de l'exécution, ils intègrent tous l'assemblage en langage C, c'est-à-dire la «programmation hybride».

Publié 13 articles originaux · loué 4 · visites 767

Je suppose que tu aimes

Origine blog.csdn.net/yuechifanfan/article/details/105570128
conseillé
Classement