2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
dans le dernier numéro[Langage C] - Explication détaillée du prétraitement (Partie 2) Au cours de l'étude, nous avons présenté en détail les connaissances pertinentes sur les macros en prétraitement. Je pense que tout le monde y gagnera beaucoup. Ne vous inquiétez pas, continuons à acquérir d'autres connaissances sur le prétraitement dans ce numéro.
# 运算符
Convertit un argument d'une macro en chaîne littérale.Il est permis d'apparaître dans la liste de substitution des macros avec paramètres.# 运算符
L'opération effectuée peut être comprise comme une « stringification »
Qu'est-ce que cela signifie?
Faisons d’abord une préfiguration :
int mian()
{
printf("hello" "worldn");
printf("helloworldn");
return 0;
}
Quelle est la différence entre les deux lignes de code ci-dessus ? Jetons un coup d'oeil ensemble :
Comme vous pouvez le constater, l'effet de deux chaînes et d'une chaîne est le même.C语言会把两个字符串天然连成一个字符串
, ajouter un espace au milieu est inutile.
Maintenant, il y a une scène comme celle-ci :
int main()
{
int a = 1;
printf("The value of a is %dn", a);
int b = 20;
printf("The value of b is %dn", b);
float f = 8.5f;
printf("The value of f is %fn", f);
return 0;
}
Nous avons constaté que la logique des trois lignes de code est très相像
Oui, mais il y a些许不同
。
Nous avons donc pensé qu'étant donné qu'ils sont si semblables, pourrions-nous les mettre封装成一个函数
, pour plus de facilité d'utilisation ?
Mais les fonctions ne peuvent pas remplir cette fonction.
alors que devons-nous faire ?
Nous pouvons essayer d'utiliser des macros pour le résoudre
#define Print(n, format) printf("The value of n is " format "n", n)
int main()
{
int a = 1;
Print(a, "%d");
//printf("The value of a is %dn", a);
int b = 20;
Print(b, "%d");
//printf("The value of b is %dn", b);
float f = 8.5f;
Print(f, "%f");
//printf("The value of f is %fn", f);
return 0;
}
résultat de l'opération :
nous découvrons nnn Il n'a pas changé, alors comment dois-je le modifier ?
C'est ici que notre opérateur # doit être utilisé :# Convertit un argument d'une macro enchaîne littérale,Tout de suite nnn devenir « n » « n »“n”
À ce stade, nous pouvons utiliser la méthode d'épissage pour devenir
#define Print(n, format) printf("The value of " #n " is " format "n", n)
je ne sais pas ?Vous comprendrez après avoir lu l’explication ci-dessous.
##
peut être localisé en luiLes symboles des deux côtés sont combinés en un seul symbole, qui permet la définition de macros从分离的文本片段创建标识符
。##
est appelémarquage de collage .Une telle connexion doit produire un合法
indicateur, sinon le résultat est indéfini.
Nous avons déjà dit que pour écrire une fonction qui trouve la plus grande valeur de deux nombres, vous devez écrire différentes fonctions pour différents types de données.
int int_max(int x, int y)
{
return x > y ? x : y;
}
float float_max(float x, float y)
{
return x > y ? x : y;
}
C'est inévitablement trop lourd et il existe de nombreuses similitudes entre les deux fonctions.
Existe-t-il un moyen de créer rapidement une telle fonction ?comme une fonctionMouleIdem, appliquez simplement une fonction et elle sortira
On peut en écrire un comme ça宏
:
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
GENERIC_MAX(int); //相当于定义了一个函数int_max
GENERIC_MAX(float); //相当于定义了一个函数float_max
int main()
{
int r1 = int_max(3, 5);
printf("%dn", r1);
float r2 = float_max(2.3f, 7.6f);
printf("%fn", r2);
return 0;
}
résultat de l'opération :
Nous pouvons aussi gccgccgcc Observer les résultats prétraités dans l’environnement.i
fichier, ayez une compréhension plus intuitive de
Bien entendu, la fonction générée de cette manière est également peu pratique à déboguer.
Alors ici ##
Quel rôle joue-t-il ?
ajouter ##
, le compilateur pensera qu'il s'agit d'un symbole
Jetons un coup d'oeil à Kanga##
Effet:
De manière générale, la syntaxe d'utilisation des fonctions et des macros est très similaire.语言本身没法帮我们区分二者
Une de nos habitudes habituelles est :
- Nommer la macrotoutes en majuscules
- Nom de la fonctionN'utilisez pas toutes les majuscules
Bien entendu, ces règles de dénomination ne sont pas absolues.
Par exemple décalage décalageouuffset Cette macro est écrite en minuscules
Note: décalage décalageouuffset Il est utilisé pour calculer le décalage des éléments de la structure par rapport à la position de départ de la structure.
# indéfini indéfinitoindettttF Les instructions sont utilisées pourSupprimer une définition de macro
Le code ci-dessus est utilisé à la ligne 169# indéfini indéfinitoindettttF Suppression de la macro MAX.Il n'y a aucun problème lors de l'appel des 168 lignes avant la suppression, mais une erreur sera signalée lors de l'appel des 170 lignes après la suppression.
De nombreux compilateurs C (sans compter VS) offrent la possibilité de définir des symboles sur la ligne de commande.Utilisé pour démarrer le processus de compilation
Par exemple : Cette fonctionnalité est utile lorsque l'on souhaite compiler différentes versions d'un programme basées sur le même fichier source. (Supposons qu'un tableau d'une certaine longueur soit déclaré dans un programme. Si la mémoire de la machine est limitée, nous avons besoin d'un très petit tableau, mais si la mémoire d'une autre machine est plus grande, le tableau dont nous avons besoin peut être plus grand)
La définition de la ligne de commande est dansétape de prétraitementTraité, en phase de prétraitement, dans le code ci-dessus d d dsz La valeur de a été déterminée
Lors de la compilation d'un programme, il est très difficile d'en compiler ou d'en abandonner un (un groupe d'instructions).方便
de.parce que nous pouvons utiliserdirective de compilation conditionnelle
L'instruction de compilation conditionnelle est ce code我想让你编译就编译,不想让你编译你就不要编译了
. On peut lui poser une condition Si la condition est vraie, ce code sera compilé. Si la condition est fausse, ce code ne sera pas compilé.
Par exemple:
Il serait dommage de supprimer du code de débogage, mais ce serait un moyen de le conserver, afin de pouvoir le compiler de manière sélective.
Instructions de compilation conditionnelle couramment utilisées :
#if 常量表达式
//···
#endif
#if 常量表达式
//···
#elif 常量表达式
//···
#else
//···
#endif
Quelle déclaration est vraie, cette déclaration est exécutée
#define M 1
int main()
{
#if M == 0
printf("hellon");
#elif M == 1
printf("worldn");
#elif M == 2
printf("csdnn");
#endif
printf("886n");
return 0;
}
#if defined(symbol)
#ifdef symbol
//上面两个的反面
if !defined(symbol)
#ifndef symbol
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
# include "filename"
Stratégie de recherche : premier entréLe répertoire du projet où se trouvent les fichiers sourcesSi le fichier d'en-tête n'est pas trouvé, le compilateur recherchera le fichier d'en-tête de la fonction bibliothèque de la même manière.Recherche d'emplacement standardfichier principal
Si vous ne parvenez pas à le retrouverErreur de compilation
Linux LinuxLdansux Le chemin du fichier d'en-tête standard de l'environnement (où le fichier d'en-tête est placé) :
/usr/include
Chemin du fichier d'en-tête standard pour l'environnement VS :
C:Program Files (x86)Microsoft Visual Studio 12.0VCinclude
//这是VS2013的默认路径
#include <filename.h>
Recherchez le fichier d'en-tête et accédez directement àchemin standardAllez chercher, et si vous ne le trouvez pas, vous recevrez une invite.Erreur de compilation。
Cela signifie-t-il qu’il peut également être utilisé pour les fichiers de bibliothèque ?“ ”
Le formulaire contient
la réponse estaffirmerOui, mais la recherche se fait de cette façonmoins efficace, bien sûr, c'est aussi le caspas facile à distinguerEst-ce un fichier de bibliothèque ou un fichier local ?
Après avoir étudié les précédents (compilation et liaison), on sait que l'inclusion des fichiers d'en-tête lors de l'étape de prétraitement est直接将该文件的代码拷贝到包含头文件的地方
Si un fichier d'en-tête est inclus 10 fois, il est en réalité compilé 10 fois. S'il est inclus à plusieurs reprises, la pression lors de la compilation sera plus grande.
test . c test.ctent.c
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
return 0;
}
test . h test.htent.h
void test();
struct Stu
{
int id;
char name[20];
};
Mais dans un projet, un fichier sera forcément inclus plusieurs fois, alors comment résoudre ce problème ?
Répondre:compilation conditionnelle
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
Comment le comprendre ?
- Lors de l'inclusion du fichier d'en-tête pour la première fois, doit-il être compilé ?juger d'abord
- Le symbole __TEST_H__ n'est pasnon défini,vouloircompiler
- Immédiatement aprèsDéfinir le symbole __TEST_H__
- Ensuite, incluez à nouveau le fichier d'en-tête et recherchez __TEST_H__a été défini,plus maintenantPour le fichier d'en-tête inclus ultérieurement, effectuezcompiler
Cependant, la manière d’écrire ci-dessus est plus gênante. Il existe une autre façon d’écrire :
#pragma once
L'effet est le même que la méthode ci-dessus
Cela évite l'introduction répétée de fichiers d'en-tête
#error
#pragma
#line
···
#pragma pack()//在结构体部分介绍
Les amis intéressés peuvent lire "Anatomie approfondie du langage C"
D'accord, c'est toutes les connaissances sur le prétraitement dans ce numéro. J'espère que ce blog pourra vous être utile. En même temps, corrigez-moi s'il y a des erreurs, et progressons ensemble sur la voie de l'apprentissage du langage C !