le mie informazioni di contatto
Posta[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Ci sono alcune impostazioni in linguaggio CSimboli predefiniti, possono essere utilizzati direttamente, i simboli predefiniti sono在预处理期间处理的
。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译日期
__TIME__ //文件被编译那一瞬的时间
__STDC__ //如果编译器遵循ANSI C(标准C),其值为1,否则未定义(报错)
Esempio:
#include<stdio.h>
int main()
{
printf("%sn", __FILE__);
printf("%dn", __LINE__);
printf("%sn", __DATE__);
printf("%sn", __TIME__);
return 0;
}
risultato dell'operazione:
Vorrei menzionare qui che VS non supporta completamente ANSI C (standard C); gcc gccGc.c. Supporta ANSI C (standard C)
Sintassi di base:
# define name stuff
Per esempio:
#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__ )
- La seconda frase è pigrizia, perché?
- La terza frase per perFO Circolare
初始化、判断、调整都可以省略
, ma se il giudizio viene omesso, significa che la condizione del giudizio è sempre vera, cioèciclo infinito- È meglio non farlo nel quarto gioco, potrebbe facilmente causare problemi.
- La quinta frasecarattere di continuazione della rigaÈ prevenire problemi dopo la ramificazione. La sua essenza è
转义
Indietro回车符
, in modo che il ritorno a capo non sia più un ritorno a capo.Non può esserci nulla dopo il carattere di continuazione della riga, premere“”
Basta premere Invio, altrimenti la continuazione non sarà la seguente riga di codice.
Ora arriva il problema: usa # definire definireDeFIne Quando definisci un identificatore, dovresti aggiungerlo alla fine?;
?
Per esempio:
#define MAX 1000
#define MAX 1000;
int main()
{
int n = MAX;
return 0;
}
Il codice sopra più;
, sembra un po' ridondante, ma non ha alcun impatto sul funzionamento del programma.
Sembra aggiungere;
Oppure non aggiungere;
Andrà tutto bene?
è davvero così?
Diamo un'occhiata al seguente esempio:
//例一
int main()
{
printf("%dn", MAX);
return 0;
}
//例二
int mian()
{
int max = 0;
if (1)
max = MAX;
else
max = 1;
return 0
}
Dopo la sostituzione:
printf("%dn", 1000;);
Stampa1000;
Cosa significa?
if (1)
max = 1000;
;
else
max = 1;
altrimenti altroelse Chi abbinare?
Vedi, c'è qualcosa che non va, quindiutilizzo # definire definireDeFIne Quando si definisce un indicatore, non aggiungerlo successivamente;
# definire definireDeFIne Il meccanismo prevede una disposizione允许把参数替换到文本中
, questa implementazione viene spesso chiamataMacro (Marco) (Marco)(marco)O Definire la macro (definiscimacro) (definisci macro)(DeFInemacro)
La differenza tra le macro e gli identificatori delle definizioni di macro sopra è:La macro ha parametri
Ecco come viene dichiarata la macro:
#define name(parament - list) stuff
uno di loro paramento paramentoPUNRSonoeNT - elenco elencoliooST(elenco parametri) è un elenco separato da virgole di simboli che possono apparire in roba robaSTioeeff.. mezzo
Nota: paramento paramentoPUNRSonoeNT - elenco elencoliooST(lista parametri)Parentesi sinistraDeve essere con nome nomenomee accanto a, se esiste uno spazio bianco tra di loro, l'elenco degli argomenti viene interpretato come roba robaSTioeeff.. una parte di.
Esempio:
//实现一个宏,计算一个数的平方
#define SQUARE(x) x*x
int main()
{
int a = 5;
int ret = SQUARE(a);
printf("%dn", ret);
return 0;
}
risultato dell'operazione:
Come puoi vedere, il quadrato di 5 è calcolato correttamente
Ma in realtà c'è un problema con il codice sopra. Consulta il seguente frammento di codice:
int a = 5;
printf("%dn", SQUARE(a + 1));
risultato dell'operazione:
Perché è così? Il risultato di 5+1 è 36 e 6 ∗ * ∗ 6 dovrebbe essere 36. Come hai ottenuto 11?
Il problema è con le macro, lo sappiamo宏是直接替换
, il risultato della sostituzione diretta del codice precedente è:
printf("%dn", a+1*a+1);
5 + 6 + 1, il risultato è naturalmente 11
Possiamo facilmente risolvere questo problema aggiungendo parentesi su entrambi i lati della definizione della macro.
#define SQUARE(x) (x)*(x)
Quindi non c’è nessun problema con questa definizione?Diamo un’occhiata alla seguente definizione di macro
#define DOUBLE(X) (X)+(X)
Abbiamo utilizzato le parentesi nella definizione per evitare il problema precedente, ma questa macro potrebbe causare nuovi errori.
int a = 5;
printf("%dn", 10 * DOUBLE(a));
risultato dell'operazione:
Il risultato in uscita non è 100 ma 55. Il motivo è simile a quello sopra Domanda prioritaria
Soluzione:
#define DOUBLE(X) ((X)+(X))
In sintesi, quando si utilizzano le macroNon lesinare mai sulle parentesiper evitare interazioni impreviste tra operatori nei parametri o operatori adiacenti quando si utilizzano le macro.
Quando un parametro macro appare più di una volta nella definizione della macro, se il parametro haeffetto collaterale, potresti essere in pericolo quando usi questa macro, con conseguente不可预测
il risultato di. Gli effetti collaterali sono effetti permanenti quando viene valutata l'espressione.
Per esempio:
x + 1; //不带副作用
x++; //带副作用
La seguente macro MAX illustra i problemi causati dai parametri con effetti collaterali.
#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;
}
risultato dell'operazione:
Perché è così?Analizziamolo insieme
z = ((X++) > (y++) ? (x++) : (y++))
- Innanzitutto esprimi un giudizio: XXIX++ con aa ...e++ giudizio, perché è suffisso ++, quando si giudica XXIX sono 5, aa ...e è 8, 8 > 5
- Dopo aver giudicato XXIX sono le 6, aa ...e per 9
- Quindi esegui aa ...e ++, poiché è postfisso ++, il risultato è 9
- Quindi continua aa ...e Esegui l'incremento automatico, aa ...e Il risultato finale è 10
noi XXIX E aa ...e Quando sono passati alla macro, i risultati sono cambiati, soprattutto aa ...e, dopo due modifiche, hai detto che non è terribile
Quando un parametro con effetti collaterali viene passato a una macro e il parametro viene visualizzato più di una volta nella macro, anche l'effetto collaterale del parametro appare più di una volta.
Espandi nel programma n. definire definireDeFIne Ci sono diversi passaggi coinvolti nella definizione di simboli e macro
参数进行检查
, controlla se contiene # definire definireDeFIne Definito标识符
.In tal caso, verranno sostituiti per primi被插入
nella posizione originale nel programma, con i nomi dei parametri macro sostituiti dai relativi valori#define MAX(a,b) ((a) > (b) ? (a):(b))
#define M 10
int main()
{
int x = 5;
int z = MAX(x, M);
return 0;
}
MAX nel codice sopra è rappresentato anche da # definire definireDeFIne DefinitoMacro .Nell'ultima ispezione, il suo parametro M è stato sostituito. Questa volta è giunto il momento di sostituirlo.
MASSIMO ( x , 10 ) MASSIMO( x , 10 )MUNX(X,10) è sostituito da ( ( x ) > ( 10 ) (( x ) > (10)((X)>(10)
?
?
? ( x ) : ( 10 ) ) ( x ):(10))(X):(10))
certamente,宏里面嵌套宏
va anche bene
MAX(x, MAX(2, 3))
A questo punto, sostituire prima la macro nel parametro, quindi sostituire l'intera macro
Ma va notato che questo不是递归
, che è semplicemente una macro che funge da argomento per un'altra macro.递归是宏内部又调用了宏本身
。
Inoltre, quando il preprocessore cerca # definire definireDeFIne Quando si definisce un simbolo,Non viene ricercato il contenuto delle costanti stringa
Che cosa significa?Dai una castagna e capirai.
#define M 10
int main()
{
int x = 5;
int z = MAX(x, MAX(2, 3));
printf("M = %d", x);
return 0;
}
Nel codice sopraprintf("M = %d", x);
mezzo MMM non sarà sostituito da 10
La macro sopra viene utilizzata per trovare il valore più grande di due numeri. Possiamo scriverlo completamente come una funzione.
int Max(int x, int y)
{
return x > y ? x : y;
}
Abbiamo scoperto che svolgono tutti la stessa funzione.Ma per la funzione di "trovare il maggiore tra due numeri", la scrittura della macro lo farà更有优势
Alcuni
Ci sono due ragioni:
- usato per
调用函数
E函数返回
Dicodicepotrebbe richiedere più tempo dell'esecuzione effettiva di questo piccolo calcolo (quando si chiama la funzioneCrea stack frame ).Pertanto, la funzione del rapporto macro è nel programma规模
E速度
Meglio che mai- Ma ancora più importante
函数的参数必须声明类型
, che fa sì che la funzione venga utilizzata solo su espressioni del tipo appropriato.Al contrario, questa macro può essere applicata a molti tipi: è possibile utilizzare intero, intero lungo, virgola mobile, ecc.
>
Per confrontare.I parametri della macro sonoTipo indipendenteDi。
Utilizzeremo sempre le macro in futuro?In effetti, le macro vengono utilizzate solo perCalcolo semplice, non adatto a quelle operazioni e funzioni complesse e di grandi dimensioni rispetto alle macro Svantaggi:
- Ogni volta che viene utilizzata una macro, una copia del codice di definizione della macro viene inserita nel programma.A meno che la macro non sia relativamente breve, potrebbe
大幅度增加程序的长度
- la macro è
没法调试
Di- Le macro sono indipendenti dal tipo, ovvero
不够严谨
- Le macro possono causare problemi di priorità operativa, causando problemi al programma
容易出错
Ma a volte le macro possono fare cose che le funzioni non possono fare
Per esempio:
int* p = (int*)malloc(10 * sizeof * (int));
Non ci piace scriverlo così malloc mallocmaLLoc La funzione è troppo ingombrante, lo voglio大小
E类型
Passalo per aprire spazio
Malloc(10, int);
Le funzioni possono farlo?No perchéLe funzioni non possono passare tipi
E le macro possono farlo, perché le macro noNon controllarei tuoi parametritipoDi
#define Malloc(n, type) (type*)malloc(n * sizeof(type))
int main()
{
int* p = Malloc(10, int);
return 0;
}
Un confronto tra macro e funzioni:
Attributi | # definire definireDeFIneDefinire la macro | funzione |
---|---|---|
lunghezza del codice | Ogni volta che viene utilizzato, il codice macro verrà inserito nel programma Ad eccezione delle macro molto piccole, la lunghezza del programma aumenterà in modo significativo. | Il valore del codice funzione appare in un posto e ogni volta che viene utilizzata la funzione, viene chiamato lo stesso codice in quel posto. |
Velocità di esecuzione | Più veloce | C'è il sovraccarico aggiuntivo delle chiamate di funzione e dei ritorni (apertura degli stack frame), quindi iniziamo con quelli più lenti. |
precedenza dell'operatore | I parametri macro vengono valutati nel contesto di tutte le espressioni circostanti. A meno che non vengano incluse le parentesi, la precedenza degli operatori adiacenti potrebbe avere conseguenze imprevedibili. Pertanto, si consiglia di scrivere le macro con più parentesi. | I parametri della funzione vengono valutati solo una volta quando viene chiamata la funzione e il relativo valore del risultato viene passato alla funzione, rendendo più prevedibile il risultato della valutazione dell'espressione. |
Parametri con effetti collaterali | I parametri possono essere sostituiti in più posizioni nella macro Se i parametri della macro vengono valutati più volte, la valutazione dei parametri con effetti collaterali può produrre risultati imprevedibili. | I parametri della funzione vengono chiamati solo una volta durante il passaggio dei parametri e i risultati sono più facili da prevedere. |
Tipo di parametro | I parametri della macro non hanno nulla a che fare con il tipo. Finché l'operazione sui parametri è legale, può essere utilizzata per qualsiasi tipo di parametro. | I parametri di una funzione sono correlati al tipo Se i parametri sono di tipo diverso, sono necessarie funzioni diverse, anche se eseguono la stessa attività. |
eseguire il debug | Le macro sono scomode per il debug | È possibile eseguire il debug delle funzioni passo dopo passo |
ricorsione | Le macro non possono essere ricorsive | Le funzioni possono essere ricorsive |
Esiste un modo per combinare i loro vantaggi?
Introdotto in C++funzione in linea in linea in lineaInlIne ——Presenta i vantaggi sia delle macro che delle funzioni
Viene eseguito velocemente come una macro ma ha lo stesso effetto di una funzione