Põhifunktsiooni argumendid ja tagastustüüp. Kuidas kutsuda C-s ühest funktsioonist teist funktsiooni? Funktsiooni deklaratsioon ja funktsiooni määratlus. Oma raamatukogu loomine

Peamine funktsioon.

Igal C ja C++ programmil peab olema põhifunktsioon; ja see on teie otsustada, kuhu see asetate. Mõned programmeerijad asetavad selle faili algusesse, mõned aga lõppu. Kuid olenemata selle positsioonist, peate meeles pidama järgmist: "Põhi" funktsiooni argumendid. Borland C++ käivitusprotseduur saadab põhifunktsioonile kolm parameetrit (argumenti): argc, argv ja env. - argc, täisarv, on põhifunktsioonile saadetud käsureaargumentide arv, - argv on stringidele osutavate viidate massiiv (char *). DOS 3.x ja uuemates versioonides on argv määratletud kui käivitatava programmi täielik tee. Rohkema all töötades varasemad versioonid DOS argv osutab nullstringile (""). argv osutab esimesele käsureale pärast programmi nime. argv osutab teisele käsureale pärast programmi nime. argv osutab viimasele mainile saadetud argumendile. argv sisaldab NULL. - env ​​on ka stringide osutajate massiiv. Iga env-element sisaldab stringi kujul ENVVAR=väärtus. ENVVAR on nimi keskkonna muutuja, nagu PATH või 87.<значение>see on selle väärtus keskkonna muutuja, näiteks C:\DOS;C:\TOOLS (PATH jaoks) või YES (87 jaoks). Pange tähele, et kui määrate mõned neist argumentidest, peate need määrama järgmises järjekorras: argc, argv, env. Näiteks kehtivad järgmised argumentide deklaratsioonid: main() main(int argc) /* kehtib, kuid mitte väga hea */ main(int argc, char *argv) main(int argc, char *argv, char *env) Main (int) deklaratsioon argc) ei ole eriti mugav, sest teades parameetrite arvu, pole sul ise neile ligipääsu. Argument env on alati juurdepääsetav keskkonna globaalse muutuja kaudu. Vaata keskkonnamuutujat (peatükis 3) ning funktsioone putenv ja getenv (2. peatükis). argc parameetrid ja argv on ligipääsetavad ka muutujate _argc ja _argv kaudu. Näidisprogramm, mis kasutab argc, argv ja env. See on näidisprogramm ARGS.EXE, mis demonstreerib kõige lihtsam viis kasutades põhifunktsioonile edastatud argumente. /* ARGS.C programm */ #include #kaasa void main(int argc, char *argv, char *env) ( int i; printf("Argc väärtus on %d\n\n",argc); printf("In käsurida sisaldab %d parameetrit \n\n",argc); for (i=0; i<=argc; i++) printf(" argv[%d]: %s\n",i,argv[i]); printf("Среда содержит следующие строки:\n"); for (i=0; env[i] != NULL; i++) printf(" env[%d]: %s\n",i,env[i]); return 0; } Предположим, что вы запускаете программу ARGS.EXE со следующей командной строкой: C:>args first_arg "argu tühikutega" 3 4 "viimane enne üks" stopp! Pange tähele, et saate saata argumendi tühikutega, lisades selle topeltjutumärgid, nagu on näidatud näiteprogrammi kutses "argument tühikutega" ja "viimane enne üks". Programmi käivitamise tulemusena saate midagi sellist: argc väärtus on 7 Käsurea sisaldab 7 parameetrit argv: c:\turboc\testargs.exe argv: first_arg argv: arg tühjaga argv: 3 argv: 4 argv: viimane enne üks argv: stopp! Keskkond sisaldab järgmisi ridu: env: COMSPEC=C:\COMMAND.COM env: PROMPT=$p $g env: PATH=C:\SPRINT;C:\DOS;C:\BC Käsu maksimaalne kogupikkus põhifunktsioonile saadetud rida (sh tühikud ja programmi enda nimi) ei tohi ületada 128 tähemärki; Need on DOS-i piirangud. Käsurea paomärgid Käsurea argumendid võivad sisaldada paomärke. Neid saab aga laiendada kõigi argumendile vastavate failinimede puhul samamoodi nagu seda tehakse näiteks DOS-i kopeerimiskäsuga. Põgenemissümbolite kasutamiseks peate programmi linkeriga linkimisel kaasama Borland C++-ga kaasas oleva objektifaili WILDARGS.OBJ. Kui teie programmile on lisatud fail WILDARGS.OBJ, saate käsureal kasutada argumente nagu "*.*". Sel juhul sisestatakse kõigi sellele maskile vastavate failide nimed argv massiivi. Maksimaalne suurus argv massiiv sõltub ainult helitugevusest dünaamiline ala mälu. Kui antud maski jaoks sobivaid faile ei leitud, edastatakse argument sellisel kujul, nagu see käsureale kirjutati. (See tähendab, et põhifunktsioonile edastatakse paomärke sisaldav string). Jutumärkides ("...") olevaid argumente ei laiendata. Näide. Järgmised käsud kompileerivad faili ARGS.C ja linkivad selle mooduliga WILDARGS.OBJ ning seejärel käivitage saadud programm ARGS.EXE: bcc args wildarg.obj args C:\BORLANDC\INCLUDE\*.H "*.C" ARGS.EXE-i käivitamisel laieneb esimene argument kõigi H-laiendiga failide nimedele kataloogis Borland C++ INCLUDE. Pange tähele, et kõik read sisaldavad kogu marsruuti (näiteks C:\TC\INCLUDE\ALLOC.H). *.C argumenti ei laiendata, sest see on jutumärkides. Kui töötate integreeritud keskkonnas (BC.EXE), peate lihtsalt projekti menüüs nime määrama projekti fail, mis peaks sisaldama järgmisi ridu: ARGS WILDARGS.OBJ Seejärel kasutage käsurea parameetrite määramiseks käske "Run/Arguments". Kommenteeri. Kui soovite, et paomärkide töötlemine toimuks alati, st. Selleks, et lingiredaktor saaks faili WILDARGS.OBJ automaatselt linkida, peate muutma oma standardset C?.LIB teeki, et lisada fail WILDARGS.OBJ. Selleks eemalda SETARGV teegist ja lisa WILDARGS. Seda saab teha järgmiste käskude abil (me mõtleme standardraamatukogud ja WILDARGS.OBJ sisalduvad praeguses kataloogis): TLIB-i kirjeldatakse kasutusjuhendi peatükis 7 "Utiliidid". tlib cs -setargv +wildargs tlib cc -setargv +wildargs tlib cm -setargv +wildargs tlib cl -setargv +wildargs tlib ch -setargv +wildargs Kompileerimine lülitiga -p (Pascali kutsumisleping) Kui kompileerite oma programmi Pascali kutsumiskokkuleppe abil (üksikasjalik teave peatükis 9 "Liides montaaži keelega", "Programmeerija juhend"), peate meeles pidama, et põhifunktsioon tuleb selgesõnaliselt deklareerida funktsioonina C. Seda saab teha kasutades märksõna cdecl on umbes selline: cdecl main(int argc, char *argv, char *env) Põhifunktsiooni tagastatav väärtus. Põhifunktsioon tagastab väärtuse, mis on programmi väljumiskood: see on täisarv. Kui aga teie programm kasutab väljumiseks funktsiooni exit (või _exit), on selle funktsiooni argumendiks tagastatav väärtus. Näiteks kui teie programm sisaldab kõnet: exit(1), siis on väljumiskood 1. Kui kasutate programmi käivitamiseks Borland C++ integreeritud keskkonda (BC.EXE), saate vaadata põhikoodi tagastusväärtust. funktsiooni, valides "Fail | Hangi teavet".

C-keelte perekonna võimalused on tõesti piiramatud, kuid sellel vabadusel on ka puudusi: programmeerija peab alati silma peal hoidma ja kontrollima "puhvri ületäitumist", et programm hiljem kokku ei jookseks. sinine ekraan"laias valikus Windowsi versioonid ja riistvara kasutajatelt. Needsamad kräkkerid ja tagurdajad otsivad spetsiaalselt C-programmide koodist turvaauke, kuhu saab istutada suvalise viirusekoodi, sellest rääkis autor lähemalt oma videokursuses. Õppisin seal palju ja nüüd on mu kood palju turvalisem.

Peamine funktsioon.

Igal C ja C++ programmil peab olema põhifunktsioon; ja see on teie otsustada, kuhu see asetate. Mõned programmeerijad asetavad selle faili algusesse, mõned aga lõppu. Kuid olenemata selle positsioonist, peate meeles pidama järgmist: "Põhi" funktsiooni argumendid. Borland C++ käivitusprotseduur saadab põhifunktsioonile kolm parameetrit (argumenti): argc, argv ja env. - argc, täisarv, on põhifunktsioonile saadetud käsureaargumentide arv, - argv on stringidele osutavate viidate massiiv (char *). DOS 3.x ja uuemates versioonides on argv määratletud kui käivitatava programmi täielik tee. Kui töötate DOS-i varasemates versioonides, osutab argv nullstringile (""). argv osutab esimesele käsureale pärast programmi nime. argv osutab teisele käsureale pärast programmi nime. argv osutab viimasele mainile saadetud argumendile. argv sisaldab NULL. - env ​​on ka stringide osutajate massiiv. Iga env-element sisaldab stringi kujul ENVVAR=väärtus. ENVVAR on keskkonnamuutuja nimi, näiteks PATH või 87.<значение>see on antud keskkonnamuutuja väärtus, näiteks C:\DOS;C:\TOOLS (PATH jaoks) või YES (87 puhul). Pange tähele, et kui määrate mõned neist argumentidest, peate need määrama järgmises järjekorras: argc, argv, env. Näiteks kehtivad järgmised argumentide deklaratsioonid: main() main(int argc) /* kehtib, kuid mitte väga hea */ main(int argc, char *argv) main(int argc, char *argv, char *env) Main (int) deklaratsioon argc) ei ole eriti mugav, sest teades parameetrite arvu, pole sul ise neile ligipääsu. Argument env on alati juurdepääsetav keskkonna globaalse muutuja kaudu. Vaata keskkonnamuutujat (peatükis 3) ning funktsioone putenv ja getenv (2. peatükis). Parameetrid argc ja argv on saadaval ka muutujate _argc ja _argv kaudu. Näidisprogramm, mis kasutab argc, argv ja env. See on näidisprogramm ARGS.EXE, mis näitab lihtsaimat viisi põhifunktsioonile edastatud argumentide kasutamiseks. /* ARGS.C programm */ #include #kaasa void main(int argc, char *argv, char *env) ( int i; printf("Argc väärtus on %d \n\n",argc); printf("Käsurida sisaldab %d parameetrit \n\ n" ,argc); jaoks (i=0; i<=argc; i++) printf(" argv[%d]: %s\n",i,argv[i]); printf("Среда содержит следующие строки:\n"); for (i=0; env[i] != NULL; i++) printf(" env[%d]: %s\n",i,env[i]); return 0; } Предположим, что вы запускаете программу ARGS.EXE со следующей командной строкой: C:> args first_arg "argu tühikutega" 3 4 "viimane enne üks" stopp! Pange tähele, et saate saata argumendi tühikutega, lisades selle jutumärkidesse, nagu on näidatud programmikutses näites "argument tühikutega" ja "viimane enne üks". Programmi käivitamise tulemusena saate midagi sellist: argc väärtus on 7 Käsurea sisaldab 7 parameetrit argv: c:\turboc\testargs.exe argv: first_arg argv: arg tühjaga argv: 3 argv: 4 argv: viimane enne üks argv: stopp! Keskkond sisaldab järgmisi ridu: env: COMSPEC=C:\COMMAND.COM env: PROMPT=$p $g env: PATH=C:\SPRINT;C:\DOS;C:\BC Käsu maksimaalne kogupikkus põhifunktsioonile saadetud rida (sh tühikud ja programmi enda nimi) ei tohi ületada 128 tähemärki; Need on DOS-i piirangud. Käsurea paomärgid Käsurea argumendid võivad sisaldada paomärke. Neid saab aga laiendada kõigi argumendile vastavate failinimede puhul samamoodi nagu seda tehakse näiteks DOS-i kopeerimiskäsuga. Põgenemissümbolite kasutamiseks peate programmi linkeriga linkimisel kaasama Borland C++-ga kaasas oleva objektifaili WILDARGS.OBJ. Kui teie programmile on lisatud fail WILDARGS.OBJ, saate käsureal kasutada argumente nagu "*.*". Sel juhul sisestatakse kõigi sellele maskile vastavate failide nimed argv massiivi. Argv massiivi maksimaalne suurus sõltub ainult dünaamilise mäluala suurusest. Kui antud maski jaoks sobivaid faile ei leitud, edastatakse argument sellisel kujul, nagu see käsureale kirjutati. (See tähendab, et põhifunktsioonile edastatakse paomärke sisaldav string). Jutumärkides ("...") olevaid argumente ei laiendata. Näide. Järgmised käsud kompileerivad faili ARGS.C ja linkivad selle mooduliga WILDARGS.OBJ ning seejärel käivitage saadud programm ARGS.EXE: bcc args wildarg.obj args C:\BORLANDC\INCLUDE\*.H "*.C" ARGS.EXE-i käivitamisel laieneb esimene argument kõigi H-laiendiga failide nimedele kataloogis Borland C++ INCLUDE. Pange tähele, et kõik read sisaldavad kogu marsruuti (näiteks C:\TC\INCLUDE\ALLOC.H). *.C argumenti ei laiendata, sest see on jutumärkides. Kui töötate integreeritud keskkonnas (BC.EXE), peate lihtsalt projektimenüüs määrama projekti faili nime, mis peaks sisaldama järgmisi ridu: ARGS WILDARGS.OBJ Seejärel kasutage käsku "Run/Arguments " käske, peaksite määrama käsurea parameetrid. Kommenteeri. Kui soovite, et paomärkide töötlemine toimuks alati, st. Selleks, et lingiredaktor saaks faili WILDARGS.OBJ automaatselt linkida, peate muutma oma standardset C?.LIB teeki, et lisada fail WILDARGS.OBJ. Selleks eemalda SETARGV teegist ja lisa WILDARGS. Seda saab teha järgmiste käskudega (oletame, et standardteegid ja WILDARGS.OBJ sisalduvad praeguses kataloogis): TLIB-i kirjeldatakse kasutusjuhendi peatükis 7, Utiliidid. tlib cs -setargv +wildargs tlib cc - setargv +wildargs tlib cm -setargv +wildargs tlib cl -setargv +wildargs tlib ch -setargv +wildargs Kompileerimine lülitiga -p (Pascali kutsumisleping) Kui kompileerite oma programmi Pascali kutsumiskokkuleppe abil (üksikasjalikult kirjeldatud peatükis 9 " Koostekeelega liidestamine", "Programmeerija juhend"), peate meeles pidama, et põhifunktsioon peab olema selgelt deklareeritud funktsioonina C. Seda saab teha cdecl märksõnaga umbes järgmiselt: cdecl main(int argc, char *argv, char *env) Põhifunktsiooni tagastatud väärtus. Põhifunktsioon tagastab väärtuse, mis on programmi väljumiskood: see on täisarv. Kui aga teie programm kasutab väljumiseks funktsiooni exit (või _exit), on selle funktsiooni argumendiks tagastatav väärtus. Näiteks kui teie programm sisaldab kõnet: exit(1), siis on väljumiskood 1. Kui kasutate programmi käivitamiseks Borland C++ integreeritud keskkonda (BC.EXE), saate vaadata põhikoodi tagastusväärtust. funktsiooni, valides "Fail | Hangi teavet".

Mõned argumendid saate edastada C-programmidele. Kui main() kutsutakse arvutuse alguses, edastatakse sellele kolm parameetrit. Esimene neist määrab programmile juurdepääsul käsuargumentide arvu. Teine on rida viiteid märgistringid sisaldab neid argumente (üks argument rea kohta). Kolmas on ka hulk viiteid märgistringidele; seda kasutatakse juurdepääsuks operatsioonisüsteemi parameetritele (keskkonnamuutujatele).

Iga selline rida on esitatud järgmiselt:

muutuja = väärtus\0

Viimase rea leiab kahe lõpus oleva nulli järgi.

Nimetagem funktsiooni main() argumendid vastavalt: argc, argv ja env (võimalikud on ka muud nimed). Siis on vastuvõetavad järgmised kirjeldused:

main(int argc, char *argv)

main(int argc, char *argv, char *env)

Oletame, et draivil A on mingi programm prog.exe. Käsitleme seda järgmiselt:

V:\>prog.exe fail1 fail2 fail3

Siis argv on kursor reale A:\prog.exe, argv on kursor reale file1 jne. Esimesele tegelikule argumendile osutab argv ja viimasele argv. Kui argc=1, siis ei ole käsureal programmi nime järel parameetreid. Meie näites argc=4.

Rekursioon

Rekursioon on kutsumismeetod, milles funktsioon viitab iseendale.

Oluline punkt rekursiivse programmi koostamisel on väljundi organiseerimine. Lihtne viga on see, et funktsioon kutsub ennast järjestikku lõputult. Seetõttu peab rekursiivne protsess samm-sammult ülesannet lihtsustama, et lõpuks ilmuks sellele mitterekursiivne lahendus. Rekursiooni kasutamine ei ole alati soovitav, kuna see võib viia virna ülevooluni.

Raamatukogu funktsioonid

Programmeerimissüsteemides kombineeritakse sageli ettetulevate probleemide lahendamise rutiinid teekideks. Selliste ülesannete hulka kuuluvad: matemaatiliste funktsioonide arvutamine, andmete sisestamine/väljund, stringide töötlemine, interaktsioon operatsioonisüsteemi tööriistadega jne. Teegi rutiinide kasutamine vabastab kasutaja vajadusest töötada välja sobivad tööriistad ja annab talle lisateenus. Teekides sisalduvad funktsioonid on varustatud programmeerimissüsteemiga. Nende deklaratsioonid on antud *.h-failidena (need on nn kaasamis- või päisefailid). Seetõttu, nagu eespool mainitud, peaksid raamatukogu funktsioonidega programmi alguses olema read nagu:

#kaasa<включаемый_файл_типа_h>

Näiteks:

#kaasa

Samuti on olemas võimalused kasutajaprogrammidega raamatukogude laiendamiseks ja uute loomiseks.

Globaalsetele muutujatele eraldatakse kogu programmi kestuse ajaks mälus kindel koht. Kohalikud muutujad salvestatakse virna. Nende vahel on mäluala dünaamiliseks jaotamiseks.

Dünaamilise jaotuse jaoks kasutatakse funktsioone malloc() ja free(). vaba mälu. Funktsioon malloc() eraldab mälu, funktsioon free() vabastab selle. Nende funktsioonide prototüübid on salvestatud päisefaili stdlib.h ja need näevad välja järgmised:

void *malloc(suurus_t suurus);

void *free(void *p);

Funktsioon malloc() tagastab kursori tüüp tühi; Nõuetekohaseks kasutamiseks tuleb funktsiooni väärtus teisendada vastavat tüüpi osutiks. Kui see õnnestub, tagastab funktsioon kursori vaba mälu suuruse esimesele baidile. Kui mälu pole piisavalt, tagastatakse väärtus 0. Muutuja jaoks vajalike baitide arvu määramiseks kasutage toimingut sizeof().

Nende funktsioonide kasutamise näide:

#kaasa

#kaasa

p = (int *) malloc(100 * sizeof(int)); /* Eraldage mälu 100 jaoks

täisarvud */

printf("Pole piisavalt mälu\n");

jaoks (i = 0; i< 100; ++i) *(p+i) = i; /* Использование памяти */

jaoks (i = 0; i< 100; ++i) printf("%d", *(p++));

vaba(p); /* Vaba mälu */

Enne malloc() tagastatud kursori kasutamist peate veenduma, et mälu on piisavalt (osuti ei ole null).

Eeltöötleja

C-eelprotsessor on programm, mis töötleb kompilaatori sisendit. Eelprotsessor vaatab lähteprogrammi ja teeb järgmised toimingud: ühendab sellega määratud failid, teostab asendusi ja kontrollib ka kompileerimistingimusi. Sümboliga # algavad programmiread on mõeldud eelprotsessori jaoks. Ühele reale on lubatud kirjutada ainult üks käsk (eelprotsessori direktiiv).

direktiiv

#define identifikaatori asendamine

põhjustab nimega identifikaatori asendamise järgnevas programmitekstis asendustekstiga (pange tähele, et selle käsu lõpus ei ole semikoolonit). Sisuliselt tutvustab see direktiiv makrodefinitsiooni, kus "identifikaator" on makrodefinitsiooni nimi ja "asendamine" on märgijada, millega eeltöötleja määratud nime asendab, kui ta selle programmi tekstist leiab. Makrodefinitsiooni nimetus on tavaks kirjutada suurtähtedega.

Vaatame näiteid:

Esimene rida paneb programmi asendama identifikaatori MAX konstandiga 25. Teisel real on võimalik kasutada tekstis sõna BEGIN, mitte avava lokkis sulu (().

Pange tähele, et kuna eelprotsessor ei kontrolli makrodefinitsioonide sümboolsete nimede ja nende kasutamise konteksti ühilduvust, on soovitatav selliseid identifikaatoreid defineerida mitte käskkirjaga #define, vaid kasutades märksõna const koos selgesõnalise viitega tüüp (see kehtib suuremal määral C++ puhul):

const int MAX = 25;

(int tüübi võib ära jätta, kuna see on vaikimisi).

Kui #define direktiiv näeb välja selline:

#define identifikaator (identifikaator, ..., identifikaator) asendus

ja esimese identifikaatori ja avasulgu vahel ei ole tühikut, siis see on argumentidega makroasenduse definitsioon. Näiteks pärast rida nagu:

#define READ(val) scanf("%d", &val)

lause READ(y); käsitletakse samamoodi nagu scanf("%d",&y);. Siin val on argument ja teostatakse makroasendus argumendiga.

Kui asenduses on pikad määratlused, mis jätkuvad jaoks järgmine rida, järgmise rea lõppu koos jätkuga pannakse sümbol \.

Saate lisada ##-ga eraldatud objektid makrodefinitsioonidesse, näiteks:

#define PR(x, y) x##y

Pärast seda kutsub PR(a, 3) asendust a3. Või näiteks makrodefinitsioon

#define z(a, b, c, d) a(b##c##d)

tulemuseks on z(sin, x, +, y) asendamine sin(x+y).

Makroargumendi ette asetatud sümbol # näitab, et see teisendatakse stringiks. Näiteks pärast käskkirja

#define PRIM(var) printf(#var"= %d", vari)

järgmine fragment programmi tekstist

teisendatakse järgmiselt:

printf("aasta""= %d", aasta);

Kirjeldame teisi eelprotsessori direktiive. #include direktiivi on varemgi nähtud. Seda saab kasutada kahel kujul:

#include "failinimi"

#kaasa<имя файла>

Mõlema käsu ülesandeks on kaasata failid koos määratud nimi. Esimene neist laadib faili praegusest kataloogist või prefiksina määratud kataloogist. Teine käsk otsib faili programmeerimissüsteemis määratletud standardsetest asukohtadest. Kui faili, mille nimi on kirjutatud jutumärkides, ei leita määratud kataloog, siis jätkatakse otsingut käsu #include jaoks määratud alamkataloogides<...>. #include direktiive saab üksteise sisse pesastada.

Järgmine käskkirjade rühm võimaldab valikuliselt kompileerida programmi osi. Seda protsessi nimetatakse tingimuslikuks kompileerimiseks. Sellesse rühma kuuluvad direktiivid #if, #else, #elif, #endif, #ifdef, #ifndef. #if direktiivi kirjutamise põhivorm näeb välja selline:

#if konstantne_avaldisjada_operaatorite_jada

Siin kontrollitakse konstantse avaldise väärtust. Kui see on tõene, siis täidetakse määratud lausete jada ja kui see on väär, siis jäetakse see lausejada vahele.

Käsu #else tegevus sarnaneb C-keele käsu else tegevusega, näiteks:

#kui konstantne_avaldis

lause_jada_2

Siin, kui konstantne avaldis on tõene, siis käivitatakse operaatori_jada_1 ja kui väär, siis operaatori_jada_2.

Direktiiv #elif tähendab "muu kui" toimingut. Selle kasutamise põhivorm on:

#kui konstantne_avaldis

lause_jada

#elif konstantne_avaldis_1

lause_jada_1

#elif konstantne_avaldis_n

väidete_jada_n

See vorm sarnaneb C-keele konstruktsiooniga: if...else if...else if...

direktiiv

#ifdef identifikaator

määrab, kas see on määratletud Sel hetkel määratud identifikaator, st. kas see sisaldub sellistes direktiivides nagu #define. Vormi string

#ifndef identifikaator

kontrollib, kas määratud identifikaator on hetkel määramata. Kõigile nendele käskkirjadele võib järgneda suvaline arv tekstiridu, mis võivad sisaldada lauset #else (#elif ei saa kasutada) ja lõppeda reaga #endif. Kui kontrollitav tingimus on tõene, siis ignoreeritakse kõiki ridu #else ja #endif vahel ning kui Väär, siis kontrolli ja #else vahel olevaid ridu (kui sõna #else pole, siis #endif). #if ja #ifndef direktiivid saab üksteise sisse pesastada.

Vaata käskkirja

#undef identifikaator

põhjustab määratud identifikaatori määratlemata jätmise, st. ei kuulu asendamisele.

Vaatame näiteid. Kolm järgmist direktiivi:

kontrolli, kas WRITE identifikaator on defineeritud (ehk kas oli selline käsk nagu #define WRITE...), ja kui nii, siis hakatakse WRITE nime pidama määratlemata, st. ei kuulu asendamisele.

direktiivid

#define KIRJUTA fprintf

kontrollib, kas WRITE identifikaator on määratlemata, ja kui jah, siis määratakse fprintf nime asemel WRITE identifikaator.

Direktiiv #error on kirjutatud järgmisel kujul:

#error error_message

Kui see esineb programmi tekstis, kompileerimine peatub ja ekraanile kuvatakse veateade. Seda käsku kasutatakse peamiselt silumisfaasis. Pange tähele, et veateadet ei pea olema jutumärkides.

Direktiiv #line on mõeldud C programmeerimissüsteemis määratletud muutujate _LINE_ ja _FILE_ väärtuste muutmiseks. Muutuja _LINE_ sisaldab käivitatud programmi reanumbrit Sel hetkel aega. Identifikaator _FILE_ on kursor stringile koos kompileeritava programmi nimega. #line käskkiri on kirjutatud järgmiselt:

#rea number "faili_nimi"

Siin on number mis tahes positiivne täisarv, mis määratakse muutujale _LINE_, faili_nimi on valikuline parameeter, mis alistab _FILE_ väärtuse.

Direktiiv #pragma võimaldab teil kompilaatorile edastada mõned juhised. Näiteks joon

näitab, et C-programm sisaldab montaažikeele stringe. Näiteks:

Vaatame mõningaid globaalseid identifikaatoreid või makronimesid (makrodefinitsiooni nimesid). Määratletakse viis sellist nime: _LINE_, _FILE_, _DATE_, _TIME_, _STDC_. Kahte neist (_LINE_ ja _FILE_) on juba eespool kirjeldatud. Identifikaator _DATE_ määratleb stringi, milles edastamise kuupäev on salvestatud lähtefail objekti koodi sisse. Identifikaator _TIME_ määrab stringi, mis salvestab lähtefaili objektikoodiks tõlkimise aja. Makro _STDC_ väärtus on 1, kui kasutatakse standardseid makronimesid. Vastasel juhul seda muutujat ei määratleta.

Minimaalne C++ programm on

Int main() ( ) // minimaalne C++ programm

See programm sisaldab funktsiooni deklaratsiooni peamine mis ei aktsepteeri ühtegi argumenti. Traksid peegeldavad rühmitamist C++ ja in sel juhul näidata funktsiooni põhiosa peamine. See tähendab, et põhifunktsiooni algus on avatud sulg ja põhifunktsiooni lõpp on sulgev sulg. Topeltkaldkriips tähistab kommentaari algust. Kompilaator ignoreerib kommentaare ja nende eesmärk on koodis sisalduva teabe selgitamine.

Igal C++ keeles kirjutatud programmil on funktsioon peamine (), millest programm käivitub. Funktsioon main(), reeglina tagastab selle täitmise tulemuse, millest annab märku int(täisarv - täisarv), mis kirjutatakse funktsiooni ette peamine (). Õige ja eduka lõpetamise korral funktsioon peamine () tulemuseks tagasi 0 . Nullist erinev tulemuse väärtus näitab programmi ebanormaalset lõpetamist.

Programmi valmimisel tagastatavat väärtust saab kasutada operatsioonisüsteem ametlikel eesmärkidel.

Tüüpiline näide esimesest programmist mis tahes programmeerimiskeeles on tekstiväljund "Tere, Maailm!":

#kaasa int main() ( std::cout<< "Hello, World!\n"; }

Kuid kas selles programmis on kõik nii lihtne? Üldiselt sisaldab see väike programm ainuüksi väga suurt teabekihti, mida tuleb mõista, et C++ keeles areneda.

  1. direktiiv #kaasa
    #kaasa
    ütleb kompilaatorile, et on vaja lisada teatud päisefail, mille komponente on plaanis kasutada failis, kus funktsioon on deklareeritud peamine () . iostream on STL-i standardne I/O teek. See tähendab, et siin on juba kasutusel teekide funktsionaalsus, kuigi need on keele standard. Ja viimane punkt on nurksulud, milles raamatukogu nimi asub, mis näitavad, et see on väliste failide kaasamine projekti, mitte need, mis on projekti osa. Lisatud on samad failid, mis on osa projektist, ümbritsetuna näiteks tavaliste jutumärkidega #include "minu klass.h". See teekide ühendus on standardne. Näiteks sisse Visual Studio Selle standardi mittejärgimine toob kaasa vead.
  2. std on nimeruumi kasutamine, milles väljundlause asub cout. Nimeruumid võeti kasutusele C++-s, et eemaldada nimekonfliktid teekide ja arendaja projekti vahel, kui funktsioonide või klasside nimed on kuskil dubleeritud. Java kasutab nimekonfliktide lahendamiseks paketisüsteemi.

    cout on väljundoperaator, millel on ülekoormatud operaator << et vältida eraldi funktsiooni kasutamist teksti väljastamiseks konsooli.

See on lisaks funktsiooni kirjutamisele peamine võib esineda erineval kujul, kuigi standardsed on kaks kirjet:

  1. int main()
  2. int main(int argc, char* argv)

Samuti võite leida selliseid rekordeid nagu void main() jne. Kuid need on ekslikud kirjed, kuigi mõnes kompilaatoris nad kompileerivad isegi ilma vigade ja hoiatusteta.

Salvestuses int main(int argc, char* argv) argumendid on vastu võetud:

  1. argc- näitab läbitud argumentide arvu. Alati vähemalt 1, kuna programmi nimi edastatakse alati
  2. argv- näpunäidete massiiv argumentidele, mis edastatakse stringimuutujatena.

Kui argc suurem kui 1, tähendab see, et programmi käivitamisel anti täiendavaid argumente.

Tšekk võib välja näha selline:

#kaasa int main(int argc, char* argv) ( // Kui lisaargument on läbitud, if (argc > 1) ( // siis proovime trükkida saadud argumendi std::cout<< argv<

Üldiselt on C++-s ka väikese programmi puhul palju punkte, millest tuleb aru saada, aga see teeb asja ainult huvitavamaks ;-)

9 vastust

Mõned C-keele funktsioonid algavad häkkidena, mis just töötasid.

Üks neist funktsioonidest on mitu allkirja nii põhi- kui ka muutuva pikkusega argumentide loendite jaoks.

Programmeerijad on märganud, et nad suudavad anda funktsioonile täiendavaid argumente ja nende kompilaatoriga ei juhtu midagi hullu.

See kehtib juhul, kui kutsumiskokkulepped on järgmised:

  • Kutsumisfunktsioon tühjendab argumendid.
  • Vasakpoolseimad argumendid on virna ülaosale või virnaraami põhjale kõige lähemal, seega ei muuda valed argumendid adresseerimist kehtetuks.

Üks tingimuskutsete komplekt, mis järgib neid reegleid, on pinupõhine parameetrite edastamine, mille tulemusel väljastab helistaja argumente ja need paigutatakse paremalt vasakule:

;; pseudo-assamblee-keel ;; main(argc, argv, envp); helista push envp ;; parempoolseim argument push argv ;; push argc ;; kõige vasakpoolsem argument jõuab virna ülaosas call main pop ;; helistaja koristab poppoppi

Kompilaatorites, kus seda tüüpi väljakutsumise tava on oluline, ei pea midagi erilist tegema, et toetada kahte põhitüüpi või isegi lisatüüpe. main võib olla argumentideta funktsioon, mille puhul ta ei pööra tähelepanu elementidele, mis on virnasse lükatud. Kui see on kahe argumendiga funktsioon, leiab see virna kahe ülemise elemendina argc ja argv. Kui see on platvormispetsiifiline kolme argumendiga variant koos keskkonna osutiga (tavaline laiend), töötab ka see: see leiab kolmanda argumendi kolmanda elemendina virna ülaosast.

Seega töötab fikseeritud kõne kõigil juhtudel, võimaldades programmiga seostada ühe fikseeritud käivitusprogrammi. Selle mooduli saab kirjutada C-vormingus funktsioonina, mis sarnaneb sellele:

/* Lisan envp näitamaks, et isegi populaarse platvormipõhise variandiga saab hakkama. */ extern int main(int argc, char **argv, char **envp); void __start(void) ( /* See on käivitatava faili tõeline käivitusfunktsioon. See teostab hulga teegi initsialiseerimist. */ /* ... */ /* Ja siis: */ exit(main(argc_from_somewhere, argv_from_somewhere, envp_from_somewhere)); )

Teisisõnu, see esialgne moodul kutsub alati välja kolme argumendiga põhiargumendi. Kui main ei võta argumente või lihtsalt int, siis char ** töötab see hästi ja ka siis, kui see ei võta kutsumiskokkulepete tõttu argumente.

Kui te oma programmis selliseid asju teeksite, poleks see kaasaskantav ja seda käsitleks ISO C määratlemata käitumisena: funktsiooni deklareerimine ja väljakutsumine ühel viisil ning selle defineerimine teisel viisil. Kuid kompilaatori käivitamise trikk ei tohiks olla kaasaskantav; see ei järgi kaasaskantavate programmide reegleid.

Kuid oletame, et kutsumisreeglid on sellised, et nad ei saa nii töötada. Sel juhul peab kompilaator käsitlema maini spetsiaalselt. Kui ta märkab, et kompileerib põhifunktsiooni, saab ta genereerida koodi, mis ühildub näiteks kolme argumendiga.

Nii et sa kirjutad seda:

Int main(void) ( /* ... */ )

Kuid kui kompilaator seda näeb, teostab ta sisuliselt koodi teisenduse, nii et kompileeritav funktsioon näeb välja umbes selline:

Int main(int __argc_ignore, char **__argv_ignore, char **__envp_ignore) ( /* ... */ )

välja arvatud see, et __argc_ignore nimesid pole sõna otseses mõttes olemas. Selliseid nimesid teie ulatusse ei sisestata ja kasutamata argumentide eest ei anta hoiatusi. Koodi teisendamine paneb kompilaatori väljastama õige lingiga koodi, mis teab, et peab kustutama kolm argumenti.

Teine rakendusstrateegia on see, et kompilaator või võib-olla linker genereerib kohandatud funktsiooni __start (või kuidas iganes seda nimetatakse) või valib vähemalt mitme eelkompileeritud alternatiivi hulgast. Objektifail võib salvestada teavet selle kohta, millist toetatud põhivormi kasutatakse. Komponent saab seda teavet vaadata ja valida käivitaja õige versiooni, mis sisaldab programmi definitsiooniga ühilduvat põhikõnet. C-rakendustel on tavaliselt toetatud vaid väike arv põhivorme, seega on selline lähenemine võimalik.

C99 keele kompilaatorid peavad alati käsitlema peamist mingil määral, et toetada häkkimist, et kui funktsioon lõpeb ilma return-lauseta, käitub käitumine nii, nagu oleks käivitatud return 0. Seda saab jällegi vaadata koodi teisendamise kaudu. Kompilaator märkab, et on kompileeritud funktsioon nimega main. Seejärel kontrollib see, kas keha ots on potentsiaalselt ligipääsetav. Kui jah, lisab see tagastamise 0;

Peamine pole ülekoormatud isegi C++ keeles. Põhifunktsioon on programmi sisenemispunkt ja seal peaks olema ainult üks määratlus.

Standardse C jaoks

Hostitud keskkonna (tavalise) jaoks ütleb C99 standard:

5.1.2.2.1 Programmi käivitamine

Programmi käivitumisel kutsutavat funktsiooni nimetatakse peamiseks. Rakendus ei deklareeri selle funktsiooni prototüüpi. See tuleb määratleda tagastustüübiga int ja ilma parameetriteta:

Int main(void) ( /* ... */ )

või kahe parameetriga (siin nimetatakse argc-ks ja argv-ks, kuigi võib kasutada mis tahes nimesid, kui need on lokaalsed selle funktsiooni jaoks, milles need on deklareeritud):

Int main(int argc, char *argv) ( /* ... */ )

või samaväärne; 9) või mõni muu rakendusviis.

9) Seega saab int asendada typedefiga, mis on määratletud kui int , või tüübi argv saab kirjutada kujul char **argv jne.

Standardse C++ jaoks:

3.6.1 Põhifunktsioon

1 Programm peab sisaldama globaalset põhifunktsiooni, mis on programmi määratud algus. [...]

2 Rakendamine ei peaks määrake põhifunktsioon ette. Seda funktsiooni ei tohiks üle koormata. Sellel peab olema tagastustüüp int, kuid muul juhul on selle tüüp määratletud. Kõik rakendused peavad võimaldama peamise mõlemat järgmist definitsiooni:

Int main() ( /* ... */ )

Int main(int argc, char* argv) ( /* ... */ )

C++ standard ütleb selgesõnaliselt: "Selle [põhifunktsiooni] tagastustüüp peab olema int, kuid muidu on selle tüüp määratud rakendamisega" ja nõuab samu kahte allkirja, mis C-standardil.

IN hostitud keskkond(C-keskkond, mis toetab ka C-teeke) – operatsioonisüsteem kutsub main .

IN mittehostitav keskkond(üks on manustatud rakenduste jaoks) saate alati muuta oma programmi sisenemispunkti (või väljumist), kasutades eelprotsessori käske, näiteks

#pragma startup #pragma exit

Kui prioriteet on valikuline integraalarv.

Start Pragma täidab funktsiooni enne põhifunktsiooni (prioriteet) ja väljumispragma täidab funktsiooni pärast põhifunktsiooni. Kui käivituskäskkirju on rohkem kui üks, määrab prioriteet, milline käivitatakse esimesena.

See on C ja C++ keele üks kummalisi asümmeetriaid ja erireegleid.

Minu meelest on see ainult ajaloolistel põhjustel olemas ja mingit tõsist loogikat selle taga ei ole. Pange tähele, et main on eriline ka muudel põhjustel (näiteks main ei saa C++-s olla rekursiivne ja te ei saa võtta selle aadressi ning C99/C++ puhul võite lõpliku tagastuslause välja jätta).

Pange tähele, et isegi C++ puhul pole see ülekoormus... kas programmil on esimene vorm või teine ​​vorm; tal ei saa olla mõlemat.

Maini puhul ei ole ebatavaline see, et seda saab defineerida rohkem kui ühel viisil, seda saab defineerida ainult ühel kahest viisist.

peamine - kasutaja funktsioon; teostus ei deklareeri selle prototüüpi.

Sama kehtib ka foo või bar kohta, kuid saate nende nimedega funktsioone määratleda nii, nagu soovite.

Erinevus seisneb selles, et maini kutsub välja rakendus (käitusaeg), mitte ainult teie enda kood. Rakendamist ei piira tavaline C-funktsiooni kutsumise semantika, nii et see võib (ja peaks) käsitlema mitut võimalust, kuid ei pea käsitlema lõputult palju võimalusi. Vorm int main(int argc, char *argv) aktsepteerib käsurea argumente ja int main(void) C-s või int main() C++-s on lihtsalt mugavus lihtsate programmide jaoks, mis ei vaja käsurea argumentide töötlemist.

See, kuidas kompilaator seda käsitleb, sõltub rakendusest. Tõenäoliselt on enamikul süsteemidel väljakutsumise kokkulepped, mis muudavad need kaks vormi tõhusalt ühilduvaks, ja kõiki põhisüsteemile edastatud argumente, mis on defineeritud ilma parameetriteta, eiratakse. Vastasel juhul oleks kompilaatoril või linkeril lihtne maini spetsiaalselt käsitleda. Kui olete huvitatud sellest, kuidas see teie süsteemis töötab, võiksite vaadata mõningaid järgunimekirju.

Ja nagu paljud asjad C- ja C++-s, on detailid suuresti ajaloo ja keelte kujundajate ja nende eelkäijate meelevaldsete otsuste tulemus.

Pange tähele, et nii C kui ka C++ lubavad rakenduse main jaoks muid juurutusmääratlusi, kuid nende kasutamiseks on harva mõjuvat põhjust. Ja eraldiseisvate rakenduste (nt ilma OS-ita manustatud süsteemid) puhul on programmi sisenemispunkt juurutamise määratletud ja seda ei pruugita isegi nimetada peamiseks .

main on lihtsalt linkeri määratud algusaadressi nimi, kus main on vaikenimi. Kõik programmi funktsioonide nimed on algusaadressid, kust funktsioon algab.