2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
C-kielellä on joitain asetuksiaEnnalta määritetyt symbolit, voidaan käyttää suoraan, ennalta määritetyt symbolit ovat在预处理期间处理的
。
__FILE__ //进行编译的源文件
__LINE__ //文件当前的行号
__DATE__ //文件被编译日期
__TIME__ //文件被编译那一瞬的时间
__STDC__ //如果编译器遵循ANSI C(标准C),其值为1,否则未定义(报错)
Esimerkki:
#include<stdio.h>
int main()
{
printf("%sn", __FILE__);
printf("%dn", __LINE__);
printf("%sn", __DATE__);
printf("%sn", __TIME__);
return 0;
}
operaation tulos:
Haluaisin mainita tässä, että VS ei täysin tue ANSI C:tä (standardi C); gcc gccgcc Tukee ANSI C:tä (Standard C)
Perussyntaksi:
# define name stuff
esimerkiksi:
#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__ )
- Toinen lause on laiskuus, miksi?
- Kolmas lause vartenftai Pyöreä
初始化、判断、调整都可以省略
, mutta jos tuomio jätetään pois, se tarkoittaa, että tuomioehto on aina tosi, eliääretön silmukka- On parasta olla tekemättä tätä neljännessä pelissä, se voi aiheuttaa helposti ongelmia.
- Viides lauserivin jatkomerkkiSe on estää ongelmien syntymisen haaroittamisen jälkeen
转义
Takaisin回车符
, joten vaunun palautus ei ole enää vaunun palautus.Rivin jatkomerkin jälkeen ei voi olla mitään, paina“”
Paina vain Enter, muuten jatko ei ole seuraava koodirivi.
Nyt tulee ongelma: käytä # määritellä määritellädefsisääne Kun määrität tunnistetta, pitäisikö se lisätä loppuun?;
?
esimerkiksi:
#define MAX 1000
#define MAX 1000;
int main()
{
int n = MAX;
return 0;
}
Yllä oleva koodi plus;
, se näyttää vain hieman tarpeettomalta, mutta sillä ei ole vaikutusta ohjelman toimintaan.
Se näyttää lisäävän;
Tai älä lisää;
tuleeko kaikki hyvin?
onko se todella näin?
Katsotaanpa seuraavaa esimerkkiä:
//例一
int main()
{
printf("%dn", MAX);
return 0;
}
//例二
int mian()
{
int max = 0;
if (1)
max = MAX;
else
max = 1;
return 0
}
Vaihtamisen jälkeen:
printf("%dn", 1000;);
Tulosta1000;
Mitä tarkoittaa?
if (1)
max = 1000;
;
else
max = 1;
muuta muutaelse Ketä vertailla?
Näetkö, tässä on jotain vikaakäytä # määritellä määritellädefsisääne Kun määrität indikaattoria, älä lisää sitä sen jälkeen;
# määritellä määritellädefsisääne Mekanismi sisältää määräyksen,允许把参数替换到文本中
, tätä toteutusta kutsutaan useinMakro (marco) (marco)(marco)tai Määritä makro (definemakro ) (määrittää makro)(defsisäänemacro)
Ero makrojen ja edellä olevien makromääritelmien tunnisteiden välillä on:Makrolla on parametrit
Näin makro ilmoitetaan:
#define name(parament - list) stuff
yksi heistä paramentti paramenttisarolenent - lista listalist(argumenttiluettelo) on pilkuilla eroteltu luettelo symboleista, jotka voivat esiintyä tavaraastuff keskellä
Huomautus: paramentti paramenttisarolenent - lista listalist(parametriluettelo)Vasen sulkumerkkiTäytyy olla mukana nimi niminame vieressä, jos niiden välissä on välilyöntiä, argumenttiluettelo tulkitaan seuraavasti tavaraastuff osa.
Esimerkki:
//实现一个宏,计算一个数的平方
#define SQUARE(x) x*x
int main()
{
int a = 5;
int ret = SQUARE(a);
printf("%dn", ret);
return 0;
}
operaation tulos:
Kuten näet, 5:n neliö on laskettu oikein
Mutta itse asiassa yllä olevassa koodissa on ongelma. Katso seuraava koodinpätkä:
int a = 5;
printf("%dn", SQUARE(a + 1));
operaation tulos:
Miksi näin on? Tulos 5+1 on 36 ja 6 ∗ * ∗ 6:n pitäisi olla 36. Miten sait 11?
Ongelma on makroissa, tiedämme宏是直接替换
, niin yllä olevan koodin korvaamisen tulos on:
printf("%dn", a+1*a+1);
5 + 6 + 1, tulos on luonnollisesti 11
Voimme ratkaista tämän ongelman helposti lisäämällä sulut makromäärityksen molemmille puolille.
#define SQUARE(x) (x)*(x)
Joten eikö tässä määritelmässä ole mitään ongelmaa?Katsotaanpa seuraavaa makromääritelmää
#define DOUBLE(X) (X)+(X)
Käytimme määrittelyssä sulkeita välttääksemme edellisen ongelman, mutta tämä makro saattaa aiheuttaa uusia virheitä.
int a = 5;
printf("%dn", 10 * DOUBLE(a));
operaation tulos:
Tulos ei ole 100 vaan 55. Syy on samanlainen kuin yllä Prioriteettikysymys
Ratkaisu:
#define DOUBLE(X) ((X)+(X))
Yhteenvetona makroja käytettäessäÄlä koskaan säästä sulkeissavälttääksesi odottamattomia vuorovaikutuksia parametrien operaattorien tai vierekkäisten operaattorien välillä makroja käytettäessä.
Kun makroparametri esiintyy useammin kuin kerran makron määritelmässä, jos parametrilla onsivuvaikutus, saatat olla vaarassa käyttäessäsi tätä makroa, mikä johtaa不可预测
tulos. Sivuvaikutukset ovat pysyviä vaikutuksia, kun ilmaisua arvioidaan.
Esimerkiksi:
x + 1; //不带副作用
x++; //带副作用
Seuraava MAX-makro osoittaa sivuvaikutteisten parametrien aiheuttamat ongelmat.
#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;
}
operaation tulos:
Miksi näin on?Analysoidaan se yhdessä
z = ((X++) > (y++) ? (x++) : (y++))
- Tee ensin tuomio: xxx++ kanssa vvy++ tuomio, koska se on postfix ++, arvioitaessa xxx on 5, vvy on 8, 8 > 5
- Tuomion jälkeen xxx on 6, vvy 9:lle
- Suorita sitten vvy ++, koska se on jälkiliite ++, tulos on 9
- Jatka sitten vvy Suorita automaattinen lisäys, vvy Lopputulos on 10
me teemme xxx ja vvy Kun se siirretään makroon, tulokset ovat muuttuneet varsinkin vvy, kahden muutoksen jälkeen sanoit, että se ei ole kauheaa
Kun sivuvaikutuksia sisältävä parametri välitetään makroon ja parametri esiintyy makrossa useammin kuin kerran, myös parametrin sivuvaikutus on useammin kuin kerran.
Laajenna ohjelmassa # määritellä määritellädefsisääne Symbolien ja makrojen määrittelyyn liittyy useita vaiheita
参数进行检查
, katso sisältääkö se # määritellä määritellädefsisääne Määritelty标识符
.Jos on, ne vaihdetaan ensin被插入
alkuperäiseen paikkaan ohjelmassa, ja makroparametrien nimet korvataan niiden arvoilla#define MAX(a,b) ((a) > (b) ? (a):(b))
#define M 10
int main()
{
int x = 5;
int z = MAX(x, M);
return 0;
}
Yllä olevan koodin MAX edustaa myös # määritellä määritellädefsisääne MääriteltyMakro .Viime tarkastuksessa sen parametri M on vaihdettu. Tällä kertaa se on vaihdettava.
MAX ( x , 10 ) MAX (x, 10)MAX(x,10) korvataan merkillä ( ( x ) > ( 10 ) ((x) > (10)((x)>(10)
?
?
? ( x ) : ( 10 ) ) (x): (10))(x):(10))
varmasti,宏里面嵌套宏
se on myös hyvä
MAX(x, MAX(2, 3))
Vaihda tällä hetkellä ensin parametrin makro ja sitten koko makro
Mutta on huomattava, että tämä不是递归
, joka on vain makro, joka toimii argumenttina toiselle makrolle.递归是宏内部又调用了宏本身
。
Myös kun esiprosessori etsii # määritellä määritellädefsisääne Kun määrittelet symbolin,Merkkijonovakioiden sisältöä ei haeta
Mitä tuo tarkoittaa?Anna vain kastanja ja ymmärrät.
#define M 10
int main()
{
int x = 5;
int z = MAX(x, MAX(2, 3));
printf("M = %d", x);
return 0;
}
Yllä olevassa koodissaprintf("M = %d", x);
keskellä MMM ei korvata 10:llä
Yllä olevaa makroa käytetään kahden luvun suuremman arvon löytämiseen. Voimme kirjoittaa sen kokonaan funktiona.
int Max(int x, int y)
{
return x > y ? x : y;
}
Huomasimme, että ne kaikki suorittavat saman tehtävän.Mutta funktio "löytää suuremman kahdesta numerosta", kirjoittaa makro更有优势
Jonkin verran
Syitä on kaksi:
- käytetty
调用函数
ja函数返回
/koodisaattaa viedä enemmän aikaa kuin tämän pienen laskutoimituksen suorittaminen (kutsuttaessa funktiotaLuo pinokehys ).Siksi makrosuhdetoiminto on ohjelmassa规模
ja速度
Paremmin kuin koskaan- Vielä tärkeämpää
函数的参数必须声明类型
, jolloin funktiota käytetään vain sopivan tyyppisissä lausekkeissa.Päinvastoin, tätä makroa voidaan soveltaa useisiin tyyppeihin: voidaan käyttää kokonaislukua, pitkää kokonaislukua, liukulukua jne.
>
Verrata.Makron parametrit ovatTyyppi riippumaton/。
Käytämmekö aina makroja tulevaisuudessa?Itse asiassa makroja käytetään vainYksinkertainen laskelma, ei sovellu monimutkaisiin ja suuriin operaatioihin ja toimintoihin verrattuna makroihin Haitat:
- Joka kerta kun makroa käytetään, kopio makron määritelmäkoodista lisätään ohjelmaan.Ellei makro ole suhteellisen lyhyt, se voi olla
大幅度增加程序的长度
- makro on
没法调试
/- Makrot ovat tyypistä riippumattomia, eli
不够严谨
- Makrot voivat aiheuttaa toiminnan tärkeysjärjestysongelmia, jolloin ohjelma ei toimi
容易出错
Mutta joskus makrot voivat tehdä asioita, joihin toiminnot eivät pysty
Esimerkiksi:
int* p = (int*)malloc(10 * sizeof * (int));
Emme pidä kirjoittamisesta näin malloc mallocmalloc Toiminto on liian hankala, haluan大小
ja类型
Siirrä se yli avataksesi tilaa
Malloc(10, int);
Voivatko toiminnot tehdä tämän?Ei koskaFunktiot eivät voi läpäistä tyyppejä
Ja makrot voivat tehdä sen, koska makrot eivätÄlä tarkistaparametrisityyppi/
#define Malloc(n, type) (type*)malloc(n * sizeof(type))
int main()
{
int* p = Malloc(10, int);
return 0;
}
Makrojen ja funktioiden vertailu:
Attribuutit | # määritellä määritellädefsisääneMääritä makro | toiminto |
---|---|---|
koodin pituus | Joka kerta kun sitä käytetään, makrokoodi lisätään ohjelmaan, lukuun ottamatta hyvin pieniä makroja, ohjelman pituus kasvaa huomattavasti. | Funktiokoodin arvo näkyy yhdessä paikassa, ja joka kerta kun toimintoa käytetään, kutsutaan sama koodi kyseisessä paikassa. |
Toteutusnopeus | nopeammin | Funktion kutsuihin ja palautuksiin (pinokehysten avaamiseen) liittyy ylimääräisiä lisäkustannuksia, joten aloitetaan hitaammista. |
operaattorin etusijalla | Makroparametrit arvioidaan kaikkien ympäröivien lausekkeiden yhteydessä, ellei sulkuja sisällytetä, vierekkäisten operaattoreiden tärkeydellä voi olla arvaamattomia seurauksia. Siksi on suositeltavaa kirjoittaa makroja useammilla suluilla. | Funktioparametrit arvioidaan vain kerran, kun funktiota kutsutaan, ja sen tulosarvo välitetään funktiolle, jolloin lausekkeen arviointitulos on ennustettavampi. |
Parametrit sivuvaikutuksineen | Parametrit voidaan korvata useisiin paikkoihin makrossa. Jos makron parametrit arvioidaan useita kertoja, parametrien arviointi sivuvaikutuksineen voi tuottaa arvaamattomia tuloksia. | Toimintoparametreja kutsutaan vain kerran parametreja välitettäessä, ja tulokset on helpompi ennustaa. |
Parametrin tyyppi | Makron parametreilla ei ole mitään tekemistä tyypin kanssa Niin kauan kuin parametrien toiminta on laillista, sitä voidaan käyttää mille tahansa parametrityypille. | Toiminnon parametrit ovat tyyppikohtaisia. Jos parametrit ovat erityyppisiä, tarvitaan erilaisia toimintoja, vaikka ne suorittaisivat saman tehtävän. |
debug | Makrojen virheenkorjaus on hankalaa | Toimintoja voidaan korjata askel askeleelta |
rekursio | Makrot eivät voi olla rekursiivisia | Funktiot voivat olla rekursiivisia |
Onko mitään tapaa yhdistää niiden etuja?
Esitelty C++:ssainline-toiminto inline inlinesisäänlsisääne ——Sillä on sekä makrojen että toimintojen etuja
Se suoritetaan yhtä nopeasti kuin makro, mutta sillä on sama vaikutus kuin funktiolla