Bribe de langage C 4: utilisez _Pragma pour supprimer doucement l'API

Introduction

Imaginez ce scénario de travail: vous écrivez une bibliothèque de fonctions pour un projet , et d'autres appellent les fonctions fournies dans la bibliothèque, puis vous trouvez que la fonction A dans la bibliothèque est
redondante
.

Avec un terrain parfait, vous voulez juste jeter cette fonction A. A ce moment , vous pouvez certainement pas supprimer ce directement , parce que vous ne savez pas combien d'autres personnes ont appelé cette fonction.

Comment mieux gérer cette situation?

Parlons de ce problème dans ce court article.

Deuxièmement, le processus de fonctionnement

1. La première version de la bibliothèque

Il n'y a que 3 fichiers de test : api.h, api.c et main.c

  1. api.h et api.c: fichiers de bibliothèque, compilés libapi.so;
  2. main.c: Génère un programme exécutable, en utilisant la bibliothèque libapi.so générée ci-dessus;

api.h contenu des documents: une déclaration des deux fonctions.

contenu du fichier api.c: la définition des deux fonctions.

Compilez le fichier de bibliothèque libapi.so . Instructions de compilation:

gcc -fPIC -shared api.c -o libapi.so

Contenu du fichier Main.c:

Compilez le fichier exécutable:

gcc main.c -o main -L./ -Wl,-rpath=./ -lapi

La simplicité du code ci-dessus équivaut à helloworld.

2. La deuxième version de la bibliothèque

Maintenant, vous pensez que la fonction init est redondante . Si vous voulez la supprimer, vous pouvez la modifier comme ceci.

Dans le fichier api.c , supprimez la fonction init ().

Le contenu du fichier api.h est modifié comme suit:

Le code clé est cette ligne:

#define init()               (1) API_DEPRECATED

Maintenant que le fichier api.c a supprimé cette fonction , mais que cette fonction est appelée dans le fichier main.c, le symbole init est fourni sous la forme d' une définition de macro .

En d'autres termes:

Dans la première version, init dans le fichier main.c est une fonction , qui est traitée par le compilateur, et l'adresse de cette fonction se trouve dans la bibliothèque libapi.so pendant la phase de liaison ;

Dans la deuxième version, init est défini comme une macro , qui est remplacée par cette dernière lors de l' étape de prétraitement(1) API_DEPRECATED .

(1) est l'expression de la macro-substitution. Étant donné que cette fonction peut être utilisée dans le jugement des conditions if, elle doit renvoyer une valeur.
API_DEPRECATED est une autre définition de macro, qui est développée pour permettre au compilateur d'imprimer un message lors de la compilation du programme exécutable.

Lors de la compilation du fichier exécutable, le compilateur génère le paragraphe suivant:

gcc main.c -o main -L./ -Wl,-rpath=./ -lapi

Cela a atteint l'objectif initial! C'est pour rappeler à l'utilisateur: cette fonction est obsolète, mieux vaut ne pas l'utiliser!

Trois autres utilisations _Prama

_Pragma est similaire au mot clé __pragma spécifique à Microsoft, sauf qu'il fait partie de la norme. Il a été introduit pour C en C99 . Pour c ++, il a été introduit dans c ++ 11.
Il permet de placer des instructions dans des définitions de macro.

1. Traitement de l'inclusion répétée de fichiers d'en-tête

Dans le fichier d'en-tête, afin d'éviter une inclusion répétée , il existe généralement 3 façons de le gérer:

(1) La première approche:

#ifdef   MY_API
#define  MY_API

// 头文件内容

#endif

(2) La deuxième méthode de traitement

#pragma once

// 头文件内容

Les deux méthodes ci-dessus peuvent empêcher l'inclusion répétée du même fichier d'en-tête, mais il existe toujours des différences .

La première manière: le préprocesseur doit toujours rechercher le fichier, puis ouvrir le fichier, et après avoir lu le contenu du fichier, vérifier si MY_API a été défini.

La deuxième façon: Cela peut accélérer la vitesse de compilation, car il s'agit d'un mécanisme haut de gamme; le compilateur comparera automatiquement le nom du fichier , sans avoir besoin de juger #ifndef et #endif dans le fichier d'en-tête, de sorte que la recherche intermédiaire est omis , ouvrir et lire les opérations.

(3) La troisième approche

_Pragma("once")

La différence entre cette méthode et la deuxième méthode est:

#pragma: est une instruction de prétraitement, utilisée pour transmettre certaines informations en dehors du standard du langage au compilateur, et ne peut pas être utilisé dans les macros;
_Pragma: est un opérateur qui appartient au standard du langage, il peut donc être imbriqué dans des macros, tout comme dans l'exemple ci-dessus;

#pragma est une extension du compilateur, c'est-à-dire qu'elle est déterminée par le compilateur.Peut -être que le compilateur A le supporte, mais le compilateur B peut ne pas le supporter, bien que cette possibilité soit relativement petite.

L'opérateur _Pragma est un standard au niveau du langage . Comme il s'agit d'un standard, le compilateur doit suivre le standard , cette méthode est donc également recommandée.

Rappelez-vous que le professeur Hou Jie a dit dans la leçon vidéo C ++: Nous écrivons du code, non seulement pour assurer le bon fonctionnement , et mettons le code écrit dans une bonne ambiance ! Je pense que l'utilisation de _Pragma peut être plus atmosphérique que #ifndef.

2. Sortie des informations de compilation

#pragma message("the #pragma way")
_Pragma ("message( \"the _Pragma way\")") 

Le contenu et les informations de sortie des deux lignes ci-dessus sont identiques. Notez que les guillemets doubles imbriqués doivent être échappés par une barre oblique inverse.

C'est tout! Passez un excellent week-end!


Les bons articles doivent être envoyés ; plus vous partagez, plus vous avez de chance!


Lecture recommandée

[Langage C]
1. Pointeur de langage C - du principe sous-jacent aux compétences sophistiquées, avec des images et des codes pour vous aider à expliquer en détail
2. Le principe de débogage sous-jacent gdb original est si simple
3. Analyse étape par étape-comment utiliser C pour réaliser la programmation orientée objet
4. Une arme pour améliorer la compulsion du code: définition de macro-de l'entrée à l'abandon
5. Utilisez setjmp et longjmp en langage C pour implémenter la capture d'exceptions et la coroutine

[Conception de l'application]
1. Ils disent tous que l'architecture logicielle doit être stratifiée et divisée en modules, et comment le faire (1)
2. Ils disent tous que l'architecture logicielle doit être stratifiée et divisée en modules, et comment faire (2)
3. Développement de la passerelle IoT:
processus de conception basé sur le bus de messages MQTT (partie 1) 4. Développement de la passerelle IoT: processus de conception basé sur le bus de messages MQTT (partie 2)
5. Ma méthode de communication préférée entre processus-message bus

[Système d'exploitation]
1. Pourquoi les engins spatiaux et les missiles préfèrent-ils utiliser des microcontrôleurs plutôt que des systèmes embarqués?

[Internet des objets]
1. Ces choses sur le cryptage et les certificats
2. Approfondissez le langage de script LUA, laissez-vous comprendre pleinement le principe du débogage

[Nonsense] 1. Sur la base
de mon expérience de carrière ratée: quelques conseils pour les techniciens qui sont nouveaux sur le lieu de travail

Je suppose que tu aimes

Origine blog.csdn.net/u012296253/article/details/115366935
conseillé
Classement