2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Es gibt einige Einstellungen in der C-SpracheVordefinierte Symbole, können direkt verwendet werden, die vordefinierten Symbole sind在预处理期间处理的
。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译日期
__TIME__ //文件被编译那一瞬的时间
__STDC__ //如果编译器遵循ANSI C(标准C),其值为1,否则未定义(报错)
Beispiel:
#include<stdio.h>
int main()
{
printf("%sn", __FILE__);
printf("%dn", __LINE__);
printf("%sn", __DATE__);
printf("%sn", __TIME__);
return 0;
}
Operationsergebnis:
Ich möchte hier erwähnen, dass VS ANSI C (Standard C) nicht vollständig unterstützt; gcc gccGcc Unterstützt ANSI C (Standard C)
Grundlegende Syntax:
# define name stuff
Zum Beispiel:
#define MAX 100
#define reg register // 为 register 这个关键字创建一个简短的名字
#define do_forever for(;;) //用更形象的符号来替换一种实现
#define CASE break;case //在写 case 语句的时候自动吧 break 写上
//如果定义的 stuff 过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)
#define DEBUG_PRINT printf("file:%stline:%dt
date:%sttime:%sn" ,
__FILE__,__LINE__ ,
__DATE__,__TIME__ )
- Der zweite Satz ist Faulheit, warum?
- Der dritte Satz für fürFoder Kreisförmig
初始化、判断、调整都可以省略
, aber wenn das Urteil weggelassen wird, bedeutet dies, dass die Urteilsbedingung immer wahr istEndlosschleife- Das sollte man am besten nicht im vierten Spiel machen, da es leicht zu Ärger führen kann.
- Der fünfte SatzZeilenfortsetzungszeichenEs besteht darin, Probleme nach der Verzweigung zu verhindern
转义
Zurück回车符
, sodass der Wagenrücklauf kein Wagenrücklauf mehr ist.Nach dem Zeilenfortsetzungszeichen darf nichts mehr stehen, drücken Sie“”
Drücken Sie einfach die Eingabetaste, sonst erfolgt die Fortsetzung nicht mit der folgenden Codezeile.
Jetzt kommt das Problem: Verwenden Sie # definieren definierenDtFInt Sollten Sie beim Definieren einer Kennung diese am Ende hinzufügen?;
?
Zum Beispiel:
#define MAX 1000
#define MAX 1000;
int main()
{
int n = MAX;
return 0;
}
Der obige Code plus;
, es scheint nur ein wenig überflüssig zu sein, hat aber keinen Einfluss auf die Ausführung des Programms.
Es scheint hinzuzufügen;
Oder nicht hinzufügen;
Es wird alles gut?
Ist es wirklich so?
Schauen wir uns das folgende Beispiel an:
//例一
int main()
{
printf("%dn", MAX);
return 0;
}
//例二
int mian()
{
int max = 0;
if (1)
max = MAX;
else
max = 1;
return 0
}
Nach dem Austausch:
printf("%dn", 1000;);
Drucken1000;
Was bedeutet?
if (1)
max = 1000;
;
else
max = 1;
sonst sonsttmse Zu wem passen?
Sehen Sie, da stimmt etwas nichtverwenden # definieren definierenDtFInt Fügen Sie beim Definieren eines Indikators diesen nicht nach;
# definieren definierenDtFInt Der Mechanismus umfasst eine Bestimmung,允许把参数替换到文本中
, wird diese Implementierung oft aufgerufenMakro (Marco) (Marco)(marco)oder Makro definieren (Makro definieren) (Makro definieren)(DtFIntmacro)
Der Unterschied zwischen Makros und den oben genannten Makrodefinitionsbezeichnern ist:Makro hat Parameter
So wird das Makro deklariert:
#define name(parament - list) stuff
einer von ihnen Parament ParamentPARBintNT - Liste ListemichchST(Argumentliste) ist eine durch Kommas getrennte Liste von Symbolen, die in vorkommen können Zeug ZeugSTSieff Mitte
Notiz: Parament ParamentPARBintNT - Liste ListemichchST(Parameterliste)Linke KlammerMuss mit sein Name NameNamet nebenWenn zwischen ihnen Leerzeichen vorhanden sind, wird die Argumentliste als interpretiert Zeug ZeugSTSieff ein Teil von.
Beispiel:
//实现一个宏,计算一个数的平方
#define SQUARE(x) x*x
int main()
{
int a = 5;
int ret = SQUARE(a);
printf("%dn", ret);
return 0;
}
Operationsergebnis:
Wie Sie sehen, ist das Quadrat von 5 korrekt berechnet
Tatsächlich liegt jedoch ein Problem mit dem obigen Code vor. Bitte sehen Sie sich den folgenden Codeausschnitt an:
int a = 5;
printf("%dn", SQUARE(a + 1));
Operationsergebnis:
Warum ist das so? Das Ergebnis von 5+1 ist 36 und 6 ∗ * ∗ 6 sollte 36 sein. Wie bist du auf 11 gekommen?
Wir wissen, dass das Problem bei Makros liegt宏是直接替换
, dann ist das Ergebnis des direkten Ersetzens des obigen Codes:
printf("%dn", a+1*a+1);
5 + 6 + 1, das Ergebnis ist natürlich 11
Wir können dieses Problem leicht lösen, indem wir auf beiden Seiten der Makrodefinition Klammern hinzufügen.
#define SQUARE(x) (x)*(x)
Gibt es also kein Problem mit dieser Definition?Werfen wir einen Blick auf die folgende Makrodefinition
#define DOUBLE(X) (X)+(X)
Wir haben in der Definition Klammern verwendet, um das vorherige Problem zu vermeiden, aber dieses Makro kann neue Fehler verursachen.
int a = 5;
printf("%dn", 10 * DOUBLE(a));
Operationsergebnis:
Das Ausgabeergebnis ist nicht 100, sondern 55. Der Grund ist ähnlich wie oben. Es ist immer noch so Prioritätsfrage
Lösung:
#define DOUBLE(X) ((X)+(X))
Zusammenfassend bei der Verwendung von MakrosSparen Sie niemals an Klammernum unerwartete Interaktionen zwischen Operatoren in Parametern oder benachbarten Operatoren bei der Verwendung von Makros zu vermeiden.
Wenn ein Makroparameter mehr als einmal in der Definition eines Makros vorkommt, sofern der Parameter vorhanden istNebenwirkung, dann könnten Sie bei der Verwendung dieses Makros in Gefahr sein, was zu Folgendem führt:不可预测
das Ergebnis von. Nebenwirkungen sind dauerhafte Auswirkungen, wenn der Ausdruck ausgewertet wird.
Zum Beispiel:
x + 1; //不带副作用
x++; //带副作用
Das folgende MAX-Makro demonstriert die Probleme, die durch Parameter mit Nebenwirkungen verursacht werden.
#define MAX(a,b) ((a) > (b) ? (a):(b))
int main()
{
int x = 5;
int y = 8;
int z = MAX(x++, y++);
printf("x=%d, y=%d, z=%dn", x, y, z);
return 0;
}
Operationsergebnis:
Warum ist das so?Lassen Sie es uns gemeinsam analysieren
z = ((X++) > (y++) ? (x++) : (y++))
- Machen Sie zunächst ein Urteil: xxX++ mit JJj++ Urteil, weil es Postfix ++ ist, wenn es beurteilt wird xxX ist 5, JJj ist 8, 8 > 5
- Nach der Beurteilung xxX ist 6, JJj für 9
- Dann ausführen JJj ++, da ++ postfixiert ist, ist das Ergebnis 9
- Dann fahre fort JJj Führen Sie eine automatische Inkrementierung durch. JJj Das Endergebnis ist 10
wir werden xxX Und JJj Bei der Übergabe an das Makro haben sich insbesondere die Ergebnisse geändert JJj, nach zwei Änderungen sagten Sie, es sei nicht schrecklich
Wenn ein Parameter mit Nebeneffekten an ein Makro übergeben wird und der Parameter mehr als einmal im Makro vorkommt, tritt auch der Nebeneffekt des Parameters mehr als einmal auf.
Erweitern Sie das Programm # definieren definierenDtFInt Die Definition von Symbolen und Makros umfasst mehrere Schritte
参数进行检查
, sehen Sie, ob es # enthält definieren definierenDtFInt Definiert标识符
.Wenn ja, werden sie zuerst ersetzt被插入
an die ursprüngliche Stelle im Programm verschoben, wobei die Namen der Makroparameter durch ihre Werte ersetzt werden#define MAX(a,b) ((a) > (b) ? (a):(b))
#define M 10
int main()
{
int x = 5;
int z = MAX(x, M);
return 0;
}
MAX wird im obigen Code auch durch # dargestellt definieren definierenDtFInt DefiniertMakro .Bei der letzten Inspektion wurde sein Parameter M ersetzt. Diesmal ist es an der Zeit, ihn zu ersetzen.
MAX ( x , 10 ) MAX(x, 10)MAX(X,10) wird ersetzt durch ( ( x ) > ( 10 ) ((x) > (10)((X)>(10)
?
?
? ( x ) : ( 10 ) ) (x):(10))(X):(10))
sicherlich,宏里面嵌套宏
es ist auch in Ordnung
MAX(x, MAX(2, 3))
Ersetzen Sie zu diesem Zeitpunkt zuerst das Makro im Parameter und dann das gesamte Makro
Aber es sollte beachtet werden, dass dies不是递归
, bei dem es sich lediglich um ein Makro handelt, das als Argument für ein anderes Makro dient.递归是宏内部又调用了宏本身
。
Auch wenn der Präprozessor nach # sucht definieren definierenDtFInt Beim Definieren eines SymbolsDer Inhalt von String-Konstanten wird nicht durchsucht
Was bedeutet das?Geben Sie einfach eine Kastanie und Sie werden es verstehen.
#define M 10
int main()
{
int x = 5;
int z = MAX(x, MAX(2, 3));
printf("M = %d", x);
return 0;
}
Im obigen Codeprintf("M = %d", x);
Mitte MMM wird nicht durch 10 ersetzt
Das obige Makro wird verwendet, um den größeren Wert zweier Zahlen zu ermitteln. Wir können es vollständig als Funktion schreiben.
int Max(int x, int y)
{
return x > y ? x : y;
}
Wir haben festgestellt, dass sie alle die gleiche Funktion erfüllen.Aber für die Funktion „Finden der größeren von zwei Zahlen“ wird das Schreiben des Makros erforderlich sein更有优势
Manche
Es gibt zwei Gründe:
- benutzt für
调用函数
Und函数返回
vonCodekann mehr Zeit in Anspruch nehmen, als diese kleine Berechnung tatsächlich durchzuführen (beim Aufrufen der Funktion).Stapelrahmen erstellen ).Daher ist die Makroverhältnisfunktion im Programm enthalten规模
Und速度
Besser denn je- Wichtiger
函数的参数必须声明类型
, wodurch die Funktion nur für Ausdrücke des entsprechenden Typs verwendet wird.Im Gegenteil, dieses Makro kann auf viele Typen angewendet werden: Ganzzahl, lange Ganzzahl, Gleitkomma usw. können verwendet werden
>
Vergleichen.Die Parameter des Makros sindTypunabhängigvon。
Werden wir in Zukunft immer Makros verwenden?Tatsächlich werden Makros nur für verwendetEinfache Berechnung, im Vergleich zu Makros nicht für komplexe und große Operationen und Funktionen geeignet Nachteile:
- Bei jeder Verwendung eines Makros wird eine Kopie des Makrodefinitionscodes in das Programm eingefügt.Sofern das Makro nicht relativ kurz ist, kann dies der Fall sein
大幅度增加程序的长度
- Makro ist
没法调试
von- Makros sind typunabhängig, d. h.
不够严谨
- Makros können zu Problemen mit der Betriebspriorität führen und dazu führen, dass das Programm nicht funktioniert
容易出错
Aber manchmal können Makros Dinge tun, die Funktionen nicht können
Zum Beispiel:
int* p = (int*)malloc(10 * sizeof * (int));
Es gefällt uns nicht, es so zu schreiben malloc mallocmalloc Funktion ist zu umständlich, möchte ich大小
Und类型
Geben Sie es weiter, um Platz zu schaffen
Malloc(10, int);
Können Funktionen dies tun?Nein, weilFunktionen können keine Typen übergeben
Und Makros können es, weil Makros es nicht könnenNicht überprüfenIhre ParameterTypvon
#define Malloc(n, type) (type*)malloc(n * sizeof(type))
int main()
{
int* p = Malloc(10, int);
return 0;
}
Ein Vergleich von Makros und Funktionen:
Attribute | # definieren definierenDtFIntMakro definieren | Funktion |
---|---|---|
Codelänge | Bei jeder Verwendung wird Makrocode in das Programm eingefügt, mit Ausnahme sehr kleiner Makros, wodurch sich die Länge des Programms erheblich erhöht. | Der Funktionscodewert erscheint an einer Stelle und jedes Mal, wenn die Funktion verwendet wird, wird derselbe Code an dieser Stelle aufgerufen. |
Ausführungsgeschwindigkeit | Schneller | Es gibt einen zusätzlichen Overhead durch Funktionsaufrufe und -rückgaben (das Öffnen von Stack-Frames), also beginnen wir mit den langsameren. |
Vorrang des Operators | Makroparameter werden im Kontext aller umgebenden Ausdrücke ausgewertet, da die Priorität benachbarter Operatoren unvorhersehbare Folgen haben kann. Daher wird empfohlen, Makros mit mehr Klammern zu schreiben. | Funktionsparameter werden beim Aufruf der Funktion nur einmal ausgewertet und ihr Ergebniswert wird an die Funktion übergeben, wodurch das Auswertungsergebnis des Ausdrucks vorhersehbarer wird. |
Parameter mit Nebenwirkungen | Parameter können an mehreren Stellen im Makro ersetzt werden. Wenn die Parameter des Makros mehrmals ausgewertet werden, kann die Parameterauswertung mit Nebenwirkungen zu unvorhersehbaren Ergebnissen führen. | Funktionsparameter werden beim Übergeben von Parametern nur einmal aufgerufen und die Ergebnisse sind leichter vorherzusagen. |
Parametertyp | Die Parameter des Makros haben nichts mit dem Typ zu tun. Solange die Operation an den Parametern zulässig ist, kann er für jeden Parametertyp verwendet werden. | Die Parameter einer Funktion sind typabhängig. Sind die Parameter unterschiedlichen Typs, sind unterschiedliche Funktionen erforderlich, auch wenn sie die gleiche Aufgabe erfüllen. |
debuggen | Das Debuggen von Makros ist unpraktisch | Funktionen können Schritt für Schritt debuggt werden |
Rekursion | Makros können nicht rekursiv sein | Funktionen können rekursiv sein |
Gibt es eine Möglichkeit, ihre Vorteile zu kombinieren?
Eingeführt in C++Inline-Funktion inline inlineInmInt ——Hat die Vorteile von Makros und Funktionen
Es wird so schnell wie ein Makro ausgeführt, hat aber die gleiche Wirkung wie eine Funktion