Erinevat tüüpi transpordiliikide eelised ja puudused. Transport logistika transport. Rahvusvaheline autovedu

Tavalise Linux C kompilaatori gcc õigeks kasutamiseks peate tundma õppima käsuridade võimalusi. Lisaks laiendab gcc C-keelt. Isegi kui kavatsete kirjutada selle keele ANSI-standardile vastavat lähtekoodi, on Linuxi päiste mõistmiseks vaja vaid mõnda gcc-laiendit.

Enamik käsuridadest on samad, mida kasutavad kompilaatorid C. Mõne valiku jaoks puuduvad standardid. Selles peatükis käsitleme kõige olulisemaid võimalusi, mida igapäevases programmeerimises kasutatakse.

ISO C standardist kinnipidamine on kasulik, kuid kuna C on madala keele tase, on olukordi, kus standardvahendid pole piisavalt väljendusrikkad. Gcc-laiendusi kasutatakse laialdaselt kahes valdkonnas: kokkupuude kokkupanekukoodiga (vt http://www.delorie.com/djgpp/doc/brennan/) ja ühiskasutatavate raamatukogude loomine (vt 8. peatükk). Kuna päisefailid on osa jagatud teekidest, ilmuvad mõned laiendid ka süsteemi päisefailidesse.

Muidugi on veel palju laiendusi, mis on kasulikud mis tahes muu programmeerimise korral ja millest võib kodeerimisel väga palju abi olla. Lisateavet nende laienduste kohta leiate gcc Texinfo dokumentatsioonist.

5.1. Gcc-valikud

gcc aktsepteerib paljusid käskude võimalusi. Õnneks pole valikute komplekt, millest peate tegelikult teadlik olema, nii suurepärane ja käsitleme neid selles peatükis.

Enamik valikuid on samad või sarnased teiste kompilaatoritega, gcc sisaldab tohutut dokumentatsiooni selle võimaluste kohta, mis on saadaval info gcc kaudu (ka man gcc annab selle teabe, kuid manustamislehti ei uuendata nii sageli kui Texinfo dokumentatsiooni).

-faili nimi Määrab väljundfaili nime. See pole tavaliselt vajalik, kui kompileerite objektfaili, st vaikimisi asendatakse failinimi.c failinimega.o. Kui loote käivitatava faili, luuakse see vaikimisi (ajaloolistel põhjustel) nimega a.out. See on kasulik ka siis, kui soovite väljundfaili paigutada muusse kataloogi.
-sest Kompileerib ilma käsureale määratud lähtefaili linkimata. See loob iga lähtefaili jaoks objektifaili. Make'i kasutamisel kutsutakse gcc kompilaatorit tavaliselt iga objekti faili jaoks; seega on tõrke korral lihtsam välja selgitada, millist faili ei õnnestunud kompileerida. Kui käske käsitsi sisestate, loetletakse sageli mitu faili ühe gcc-kõnega. Kui käsureal mitme faili määratlemisel võib tekkida ebaselgus, on parem määrata ainult üks fail. Näiteks gcc -c -o a.o a.c b.c asemel on mõttekas kasutada gcc -c -o a.o b.c
-D loll Määratleb käsurida töötleja eelsed makrod. Võimalik, et peate alistama märgid, mida kest peab eriliseks. Näiteks vältige stringi määratlemisel piiritlevate märkide kasutamist. "Kaks levinumat viisi on" -Dfoo \u003d "riba" "ja -Dfoo \u003d \\" riba \\ ". Esimene viis toimib palju paremini, kui string sisaldab tühikuid, kuna kest kohtleb ruume erilisel viisil.
-Ma kataloog Lisab kataloogi kataloogide loendisse, et otsida faile.
-L kataloog Lisab kataloog teekide otsitud kataloogide loendisse; gcc eelistab jagatud teeke staatiliste asemel, kui pole teisiti täpsustatud.
- ma loll Lingid lib foo raamatukogu vastu. Kui pole teisiti öeldud, eelistab gcc ühendamist jagatud teekidega (lib foo .so) staatilistega (lib foo .a). Linker otsib funktsioone kõigist loetletud raamatukogudest nende järjestuses. Otsing lõpeb, kui kõik vajalikud funktsioonid on leitud.
-staatiline Lingi ainult staatiliste raamatukogudega. Vt 8. peatükki.
-g, -ggdb Sisaldab silumisteavet. Valik -g sunnib gcc-d lisama standardset silumisteavet. Valik -ggdb käsib teil lisada tohutul hulgal teavet, millest ainult gdb silur saab aru.
Kui kettaruum on piiratud või soovite mõne funktsiooni lingi kiiruse nimel ohverdada, peaksite kasutama -g. Sel juhul peate võib-olla kasutama mõnda muud silurit kui gdb. Kõige täieliku silumise jaoks peate määrama -ggdb. Sel juhul valmistab gcc maksimumi detailne info gdb jaoks. Tuleb märkida, et erinevalt enamikust kompilaatoritest paneb gcc optimeeritavasse koodi silumisinfot. Jälgimine optimeeritud koodide siluris võib siiski olla keeruline, sest tööajas võib juhtuda, et eeldatakse, et koodifragmendid hüpitakse ja jäetakse vahele. Siiski võite saada hea esitlus kuidas kompilaatorite optimeerimine koodi täitmise viisi muudab.
-O, -O n Sunnib koodi optimeerima gcc. Vaikimisi optimeerib gcc vähe; arvu (n) täpsustamisel viiakse optimeerimine läbi teatud tasemel. Kõige tavalisem optimeerimistase on 2; praegu on gcc-standardi kõrgeim optimeerimise tase 3. Soovitame kasutada -O2 või -O3; -O3 võib rakenduse mahtu suurendada, nii et kui see on oluline, proovige mõlemat. Kui mälu ja kettaruum on teie rakenduse jaoks olulised, võite kasutada ka suvandit -Os, mis minimeerib koodi suuruse, suurendades täitmisaega. gcc lubab sisseehitatud seadmeid ainult siis, kui rakendatakse vähemalt minimaalset optimeerimist (-O).
-ansi Kõigi ANSI standardite (X3.159-1989) või nende ISO samaväärsete (ISO / IEC 9899: 1990) (tavaliselt C89 või harvemini C90) toetamine C-programmides. Tuleb märkida, et see ei taga täielikku vastavust ANSI / ISO standardile.
Valik -ansi keelab gcc laiendid, mis on tavaliselt vastuolus ANSI / ISO standarditega. (Tulenevalt asjaolust, et neid laiendusi toetavad paljud teised C-kompilaatorid, pole see praktikas probleem.) See määratleb ka makro __STRICT_ANSI__ (nagu käesolevas raamatus hiljem kirjeldatakse), mida päisefailid kasutavad ANSI / ISO-ga ühilduva keskkonna toetamiseks.
-pedantne Kuvab kõik hoiatused ja veateated, mida nõutakse ANSI / ISO C. keelenormil. See ei taga täielikku ANSI / ISO vastavust.
-Sein Lubab genereerida kõik gcc-hoiatused, mis on tavaliselt kasulikud. Kuid see ei hõlma valikuid, mis võivad olla erijuhtudel kasulikud. Lähtekoodi suhtes kehtestatakse lint-parserile sarnane täpsusaste, gcc võimaldab teil iga kompilaatori hoiatuse käsitsi lubada ja keelata. Kõik hoiatused on täpsustatud gcc juhendis.
5.2. Päisefailid
5.2.1. pikk pikk

Pikk pikk näitab, et mäluplokk on vähemalt sama suur kui pikk. Intel i86 ja muudel 32-bitistel platvormidel on pikk 32 bitti ja pikk pikk 64 bitti. 64-bitistel platvormidel on osutid ja pikad pikad 64 bitti, samas kui pikad võivad olenevalt platvormist olla 32 või 64 bitti. Pikka pikka tüüpi toetab C99 standard (ISO / IEC 9899: 1999) ja see on pikaajaline C-laiend, mida pakub gcc.

5.2.2. Sisseehitatud funktsioonid

Mõned Linuxi päiste osad (eriti need, mis on konkreetsele süsteemile omased) kasutavad sisseehitatud funktsioone väga laialdaselt. Need on sama kiiresti kui makrod (funktsioonikõnede maksumus pole) ja pakuvad igasuguseid valideerimisi, mis on tavalise funktsioonikõne korral saadaval. Inline-funktsioone kutsuvad koodid peavad koosnema vähemalt minimaalse optimeerimise (-O) lubamisega.

5.2.3. Alternatiivsed täpsemad märksõnad

Gcc-vormingus on igal laiendatud märksõnal (märksõnad, mida ANSI / ISO standard ei hõlma) kaks versiooni: märksõna ise ja märksõna ümbritsetud kahe alljoonega mõlemalt poolt. Kui kompilaatorit kasutatakse tavarežiimis (tavaliselt kui kasutatakse varianti -ansi), siis tavalisi laiendatud märksõnu ei tuvastata. Nii tuleks päisefailis näiteks atribuudi märksõna kirjutada __attribute__.

5.2.4. Atribuudid

Laiendatud atribuudi märksõna kasutatakse gcc-le funktsiooni, muutuja või deklareeritud tüübi kohta lisateabe saamiseks, kui ANSI / ISO C-kood lubaks. Näiteks joondatud atribuut ütleb gcc-le, kuidas muutujat või tüüpi joondada; pakitud atribuut näitab, et polstrit ei kasutata; noreturn täpsustab, et funktsioon ei naase kunagi, mis võimaldab gcc-l optimeerida ja võltshoiatusi vältida.

Funktsiooni atribuudid deklareeritakse, lisades need funktsiooni deklaratsioonile, näiteks:

tühine die_die_die (int, char *) __attribute__ ((__noreturn__));

Atribuutideklaratsioon paigutatakse sulgude ja semikooloni vahele ning sisaldab atribuudi märksõna, millele järgnevad atribuudid kahekordsetes sulgudes. Kui atribuute on palju, kasutage komaga eraldatud loendit.

int printm (char *, ...)

Atribuut __ ((const,

vorming (printf, 1, 2)));

Selles näites näete, et printm ei arvesta muude väärtustega peale täpsustatud väärtuste ning sellel pole koodi genereerimisega (const) seotud kõrvalmõjusid, printm näitab, et gcc peaks kontrollima funktsiooniargumente samamoodi nagu printf () argumendid. Esimene argument on vormingustring ja teine \u200b\u200besimene asendusparameeter (vorming).

Mõnda atribuuti arutatakse edasi liikudes (näiteks 8. peatükis kirjeldades jagatud teekide kokkupanekut). Põhjalikku teavet atribuutide kohta leiate gcc Texinfo dokumentatsioonist.

Aeg-ajalt võite end vaadata Linuxi päiseid. Tõenäoliselt leiate mitmeid disainilahendusi, mis ei vasta ANSI / ISO nõuetele. Mõned neist on väärt uurimist. Kõik selles raamatus käsitletud konstruktsioonid on üksikasjalikult esitatud gcc dokumentatsioonis.

Aeg-ajalt võite end vaadata Linuxi päiseid. Tõenäoliselt leiate mitmeid disainilahendusi, mis ei vasta ANSI / ISO nõuetele. Mõned neist on väärt uurimist. Kõik selles raamatus käsitletud konstruktsioonid on üksikasjalikult esitatud gcc dokumentatsioonis.

Nüüd, kui olete C-standardi kohta teada saanud kaks või teist, vaatame lähemalt gcc-kompilaatori pakutavaid valikuid, et tagada vastavus C-standardile, milles kirjutate. Teie C-koodi standarditele vastavuse ja vigadevabaduse tagamiseks on kolm võimalust: võimalused standardi versiooni juhtimiseks, mida soovite täita, määratlused päisefailide juhtimiseks ja hoiatusvalikud, et käivitada rangemad koodide ülevaated. ...

Gcc-l on tohutu hulk võimalusi ja siin käsitleme ainult neid, mida peame kõige olulisemaks. Täieliku valikuvõimaluste loetelu leiate gcc veebikäsiraamatu lehtedelt. Samuti käsitleme lühidalt mõnda #defineerivat suvandit, mida saate kasutada; need tuleks tavaliselt täpsustada teie lähtekoodis enne mis tahes #include rida või täpsustada käsureal gcc. Võib-olla olete üllatunud võimaluste rohkuse üle valida sobiv lipp lihtsa lipu asemel, mis sunnib teid kasutama tänapäevast standardit. Põhjus on see, et paljud vanemad programmid tuginevad kompilaatorite ajaloolisele käitumisele ja nõuaksid oluliste tööde värskendamist uusimatele standarditele. Harva, kui üldse soovite värskendada kompilaatorit nii, et see hakkaks jooksukoodi katkestama. Standardite muutumisel on oluline osata töötada kindla standardi vastu, isegi kui see pole standardi uusim versioon.

Isegi kui kirjutate väikest isiklikuks kasutamiseks mõeldud programmi, kui standardite järgimine ei pruugi olla nii oluline, on sageli mõistlik lisada täiendavaid gcc-hoiatusi, et sundida kompilaatorit enne programmi käivitamist otsima teie koodist vigu. See on alati tõhusam kui siluris kood läbi vaadata ja mõelda, kus probleem võib olla. Kompilaatoril on palju võimalusi, mis väljuvad lihtsast standardikontrollist, näiteks võime tuvastada koodi, mis vastab standardile, kuid millel võib olla küsitav semantika. Näiteks võib programmil olla täitmiskäsk, mis võimaldab teil juurdepääsu muutujale enne selle initsialiseerimist.

Kui peate kirjutama programmi ühiskasutusse võtmiseks, võttes arvesse standardile vastavuse astet ja kompilaatori hoiatuste tüüpe, mis teie arvates on piisavad, on väga oluline teha natuke rohkem jõupingutusi ja lasta oma kood kompileerida ilma hoiatusteta. Kui lubate mõnda hoiatust ja harjute neid ignoreerima, võib ühel päeval olla tõsisem hoiatus, et võite jääda ilma. Kui teie kood kompileeritakse alati ilma hoiatusteadeteta, köidab uus hoiatus teie tähelepanu paratamatult. Koodi kompileerimine ilma hoiatuseta on hea komme kaasa võtta.

Kompilaatori valikud standardite jälgimiseks

Ansi on kõige olulisem standardivalik ja sunnib kompilaatorit tegutsema vastavalt ISO C90 keelenormile. See keelab mõned mittestandardsetele ühilduvatele gcc-laienditele, keelab C ++ kommentaarid (//) C-programmides ja võimaldab ANSI trigraafide (kolme märgi jada) töötlemist. Lisaks sisaldab see makro __ STRICT_ANSI__, mis keelab mõned päisefailide laiendid, mis ei ühildu standardiga. Kompilaatori järgmistes versioonides võib vastuvõetud standard muutuda.

Std \u003d - see suvand annab peenema kontrolli kasutatava standardi üle, pakkudes parameetrit, mis täpsustab täpselt nõutud standardi. Järgmised on peamised võimalused:

C89 - toetage C89 standardit;

Iso9899: 1999 - toetage ISO-standardi C90 uusimat versiooni;

Gnu89 - toetage C89 standardit, kuid lubage mõnda GNU laiendust ja mõnda C99 funktsionaalsust. See on vaikimisi versioon gcc versioonis 4.2.

Standardi jälgimise võimalused defineeritud direktiivides

On olemas konstandid (#defines), mida saab käsurealt käskudes määratleda või programmi lähtekoodis määratlustena. Me kipume arvama, et nad kasutavad kompilaatori käsurida.

STRICT_ANSI__ - sunnib teid rakendama C ISO standardit. Määratud, millal kompilaatori käsuridades on määratud suvand -ansi.

POSIX_C_SOURCE \u003d 2 - lubab funktsioone, mis on määratletud IEEE Std 1003.1 ja 1003.2. Tuleme nende standardite juurde tagasi selles peatükis veidi hiljem.

BSD_SOURCE - lubab BSD süsteemide funktsionaalsust. Kui need on vastuolus POSIX-i määratlustega, on BSD-määratlused ülimuslikud.

GNU_SOURCE - võimaldab laia valikut omadusi ja funktsioone, sealhulgas GNU laiendusi. Kui need määratlused on vastuolus POSIXi määratlustega, on viimane ülimuslik.

Hoiatuste kompilaatori valikud

Need suvandid antakse käsurealt kompilaatorile. Jällegi loetleme ainult peamised, täieliku loetelu leiate gcc veebijuhendist.

Pedantne on C-koodi puhtuse kontrollimiseks kõige võimsam variant.Lisaks võimalusele võimaldada kontrollida ka C-standardile vastavust, keelab see osa traditsioonilistest C-konstruktsioonidest, mis on standardiga keelatud, ja muudab kõik standardi GNU laiendused kehtetuks. Seda suvandit tuleks kasutada C-koodi teisaldamise maksimeerimiseks. Puuduseks on see, et kompilaator tunneb suurt muret teie programmikoodi puhtuse pärast ja mõnikord peate mõne allesjäänud hoiatusega toime tulema oma aju.

Wformat - kontrollib printf perekonna funktsioonide argumenditüüpide õigsust.

Klapid - sulgude kontrollimine ka seal, kus neid pole vaja. See suvand on väga kasulik kontrollimaks, kas keerulised struktuurid initsialiseeritakse kavandatud viisil.

Wswitch-default - kontrollib vaikesuvandi olemasolu lülituslausetes, mida üldiselt peetakse heaks kodeerimisstiiliks.

Wunused - kontrollib mitmesuguseid juhtumeid, näiteks deklareeritud, kuid kirjeldamata staatilisi funktsioone, kasutamata parameetreid, tühistatud tulemusi.

Sein - hõlmab enamiku tüüpi gcc-hoiatusi, sealhulgas kõiki eelnevaid -W-valikuid (ei hõlma ainult -pedantne). Tema abiga on lihtne saavutada programmi koodi puhtus.

Märge

Saadaval on palju täpsemaid hoiatuse valikuid, üksikasju leiate gcc-veebilehtedelt. Üldiselt soovitame kasutada -Wall; see on hea kompromiss kontrollimise vahel, mis pakub kvaliteetset programmikoodi, ja kompilaatori vahel, kes peab väljastama palju triviaalseid hoiatusi, mida on keeruline nulli viia.

GCC on lisatud igasse jaotusse Linux ja tavaliselt installitakse vaikimisi. GCC liides on tavaline UNIX-i kompilaatori liides, mis pärineb 60-ndate lõpust, eelmise sajandi 70-ndate algusest - käsurealiides. Ärge muretsege, kuna viimase aja jooksul on kasutaja interaktsiooni mehhanism antud juhul saavutatud võimalikult täiuslikuna, siis tehke koostööd GCC-ga (kui on mitu täiendavat utiliiti ja mõistlik tekstiredaktor) on lihtsam kui ükski kaasaegsest visuaalsest IDE-st. Komplekti autorid püüdsid rakenduste koostamise ja kokkupanemise protsessi võimalikult palju automatiseerida. Kasutaja kutsub juhtprogrammi gcc, tõlgendab see läbitud käsuridade argumente (suvandid ja failinimed) ning käivitab iga sisendfaili vastavalt kasutatavale programmeerimiskeelele kompilaatori, seejärel vajadusel gcc kutsub automaatselt kokku monteerija ja linker (linker).

Kummalisel kombel on kompilaatorid üks väheseid UNIX-i rakendusi, mis hoolib faililaienditest. Laiendusena määrab GCC, milline fail on selle ees ja mida sellega teha (teha) saab. Keele lähtefailid C peab olema keeles .c laiend C ++valikuliselt .cpp, päisefailid keeles C .h, .o objektifailid ja nii edasi. Kui kasutate valet laiendit, gcc ei tööta õigesti (kui olete üldse nõus, siis tehke midagi).

Liigume edasi praktika juurde. Kirjutame, koostame ja käivitame mõne lihtsa programmi. Me ei ole originaalsed, kuna selles keeles on näidisprogrammi lähtefail C Loome järgmise sisuga faili:

/ * tere.c * /

# kaasata

Peamine ( tühine )
{

Printf ("Tere maailm \\ n");

tagasi 0 ;

Nüüd väljastage kataloogis c hello.c käsk:

$ gcc hello.c

Mõne sekundi murdosa järel ilmub kataloogi a.out-fail:

$ ls
a.out tere.c

See on meie programmi valmis käivitatav fail. Vaikimisi gcc annab väljundile käivitatava nime a.out (ükskord see nimi tähendas monteerija väljund).

$ fail a.out
a.out: ELF-i 64-bitine käivitatav LSB, x86-64, versioon 1 (SYSV), dünaamiliselt lingitud (kasutab jagatud libisid), GNU / Linux 2.6.15 jaoks, ilma ribadeta

Laske tulemuseks saadud tarkvara:

$ ./a.out
Tere, Maailm


Miks on vaja käsuga faili asukoht selgesõnaliselt määrata, et käivitada fail praegusest kataloogist? Kui käivitatava faili asukohta pole selgesõnaliselt täpsustatud, otsib käske tõlgendav kest faili süsteemimuutuja PATH loetletud kataloogides.

$ echo $ PATH
/ usr / kohalik / sbin: / usr / kohalik / bin: / usr / sbin: / usr / bin: / sbin: / bin: / usr / mängud

Loendis olevad kataloogid eraldatakse koolonitähisega. Faile otsides vaatab kest katalooge kataloogide järjekorras. Vaikimisi on turvalisuse tagamiseks praegune kataloog. ei sisaldu loendis, nii et kest ei otsi selles käivitatavaid faile.

Miks ei soovitata teha. PATHIS? Usutakse, et reaalses mitmekasutajasüsteemis leidub alati mõni paha inimene, kes paigutab avalikku kataloogi pahatahtliku programmi, mille nimi on käivitatava faili nimi, mis langeb kokku mõne käsu nimega, mida kohalik superhalduri õigustega kohalik administraator sageli kutsub ... vandenõu õnnestub, kui. on kataloogide nimekirja alguses.


Utiliit faili kuvab teabe faili käsurida üle kantud tüübi kohta (süsteemi seisukohast), mõne tüüpi failide korral kuvatakse faili sisu kohta lisateave.

$ fail hello.c
hello.c: ASCII C programmi tekst
$ fail annotation.doc
annotation.doc: CDF V2 dokument, väike Endian, Os: Windows, versioon 5.1, koodileht: 1251, autor: MIH, mall: Normal.dot, viimati salvestanud: MIH, versiooni number: 83, rakenduse loomise nimi: Microsoft Kontorisõna, kogu redigeerimise aeg: 09:37:00, viimati trükitud: teisipäeval 22. jaanuaril 07:31:00 2009, loomise kellaaeg / kuupäev: esmaspäeval 12. jaanuaril 07:36:00 2009, viimane salvestatud aeg / kuupäev: teisipäeval, 22. jaanuaril 07:34:00 2009, lehekülgede arv: 1, sõnade arv: 3094, märkide arv: 17637, turvalisus: 0

See on tegelikult kõik, mida kasutajalt eduka rakenduse jaoks nõutakse. gcc :)

Väljundfaili nimi (nagu ka kõigi muude loodud failide nimed) gcc) saab muuta valikud -o:

$ gcc -o tere hello.c
$ ls
tere tere.c
$ ./hello
Tere, Maailm


Meie näites tagastab funktsioon pea () näiliselt tarbetu väärtuse 0. UNIX-ilaadsetes süsteemides on tavapärane, et pärast programmi lõpetamist tagastatakse kestale täisarv - , kui see õnnestub, muu - muidu. Kestitõlk omistab saadud väärtuse automaatselt keskkonnamuutujale nimega? ... Selle sisu saate vaadata echo $? :

$ ./hello
Tere, Maailm
$ kaja $?
0

Seda öeldi eespool gcc see on juhtimisprogramm, mis on loodud kompileerimise protsessi automatiseerimiseks. Vaatame, mis tegelikult juhtub käsu gcc hello.c täitmise tagajärjel.

Kompileerimise protsessi saab jagada 4 põhietappi: eeltöötlus, ise koostamine, kokkupanek, sidumine (ühendamine).

Valikud gcc mis tahes etapis saate protsessi katkestada.

Eeltöötleja valmistab lähtetekstifaili kompileerimiseks ette - lõikab kommentaarid välja, lisab päisefailide sisu (eeltöötluse direktiiv #include), rakendab makrode laiendamist (sümboolsed konstandid, eeltöötluse direktiiv #defineeri).

Kasutades ära variant -E järgmised sammud gcc saate eeltöötleja töödeldud faili sisu katkestada ja seda vaadata.

$ gcc -E -o hello.i hello.c
$ ls
tere.c tere.i
$ vähem tere.i
. . .
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
. . .
typedef allkirjastamata char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
. . .
extern int printf (__kontrolli täht * __ piira __vormingut, ...);
. . .
# 4 "hello.c" 2
peamine (tühine)
{
printf ("Tere maailm \\ n");
tagasi 0;
}

Pärast eeltöötleja poolt töötlemist paisus meie programmi lähtekood üles ja sai loetamatu vormi. Kood, mille me kunagi oma kätega kirjutasime, keelas faili lõpus mõne rea alla. Põhjus - kaasa arvatud standardse teegi päisefail C... Päisefail stdio.h sisaldab palju erinevaid asju ja nõuab ka muude päisefailide kaasamist.

Pange tähele faili hello.i laiendamist. Kokkulepete järgi gcc laiend .i vastab keele lähtefailidele C ei vaja eeltöötlemist. Sellised failid kompileeritakse eeltöötlejast mööda minnes:

$ gcc -o tere hello.i
$ ls
tere tere.c tere.i
$ ./hello
Tere, Maailm

Pärast eeltöötlust on käes kompileerimise kord. Kompilaator teisendab kõrgetasemelise programmi lähtekoodi koostikeele koodiks.

Sõna koostamise tähendus on udune. Näiteks vikipeedikud usuvad, viidates rahvusvahelised standardidsee kompileerimine on "kõrgetasemelises programmeerimiskeeles kirjutatud programmi lähteteksti teisendamine kompilaatori abil masinale lähedaseks keeleks või objektkoodiks". Põhimõtteliselt sobib see määratlus meile, montaažikeel on tõesti masinakeelele lähemal kui C... Kuid igapäevaelus mõistetakse kompileerimist enamasti lihtsalt mis tahes toiminguna, mis teisendab mis tahes programmeerimiskeeles oleva programmi lähtekoodi käivitatavaks koodiks. See tähendab, et protsessi, mis hõlmab kõiki nelja ülaltoodud etappi, võib nimetada ka kompileerimiseks. Selles tekstis on sarnane kahemõttelisus. Teisest küljest võib programmi lähtekoodi teisendamise keelekoodiks teisendamise toimingut tähistada ka sõnatõlkega - "ühes programmeerimiskeeles esitatud programmi teisendamine teises keeles programmiks ja teatud mõttes samaväärseks esimese keelega".

Pärast kompilatsiooni lõpuleviimist käivitatava faili loomise protsessi saate peatada variant -S:

$ gcc -S hello.c
$ ls
tere.c tere.s
$ fail hello.s
tere.s: ASCII koostaja programmi tekst
$ vähem tere.s
.fail "tere.c"
.sektsioon .andmed
.LC0:
.string "Tere maailm"
.tekst
.globl peamine
.tüüp peamine, @funktsioon
peamine:
pushl% ebp
movl% esp,% ebp
andl -16 dollarit,% esp
subl 16 dollarit,% esp
movl $ .LC0, (% esp)
kõne paneb
movl $ 0,% eax
lahkuda
ret
.suurus peamine, .- peamine


Fail hello.s ilmus kataloogi, mis sisaldab programmi rakendamist koostekeeles. Pange tähele, et väljundfaili nime täpsustamine nupuga valikud -o sel juhul seda ei nõutud, gcc genereeris selle automaatselt, asendades .c laiend algse failinimega .s Enamiku põhitoimingute jaoks gcc väljundfaili nimi moodustatakse sarnase asendamisega. Laiend .s on komplekteerimiskeelsete lähtefailide standard.

Muidugi võite käivitatava koodi hankida ka failist hello.s:

$ gcc -o hello hello.s
$ ls
tere tere.c tere.s
$ ./hello
Tere, Maailm

Monteerimistoimingu järgmine etapp on montaažikeele koodi tõlkimine masinkoodiks. Operatsiooni tulemus on objektfail. Objektifail sisaldab täitmiseks valmis masinkoodi plokke, andmeplokke, samuti failis määratletud funktsioonide ja väliste muutujate loendit ( sümbolitabel ), kuid see ei täpsusta funktsiooni ja andmeviidete absoluutseid aadresse. Objektifaili ei saa käivitamiseks otse täitmiseks, kuid hiljem (ühendamise etapis) saab seda kombineerida teiste objektide failidega (sel juhul arvutatakse sümbolitabelite kohaselt ristviidete failide vahel olevad aadressid ja need täidetakse). Võimalus gcc -c, peatab protsessi monteerimisfaasi lõpus:

$ gcc -c hello.c
$ ls
tere.c tere.o
$ fail hello.o
tere.o: ELF 64-bitine LSB ümberpaigutatav, x86-64, versioon 1 (SYSV), eemaldamata

Objektifailide standardlaiend on .o.

Kui tulemuseks olev objektfail hello.o antakse linkerile, arvutab viimane linkide aadressid, lisab programmi käivitamise ja lõpetamise koodi, raamatukogu funktsioonide väljakutsumise koodi ja selle tulemusel on meil programmi valmis käivitatav fail.

$ gcc -o tere hello.o
$ ls
tere tere.c tere.o
$ ./hello
Tere, Maailm

Mida me oleme nüüd teinud (või õigemini gcc tegi seda meie eest) ja seal on viimase etapi sisu - linkimine (linkimine, linkimine).

Noh, see seisneb kompileerimises ja ongi. Nüüd puudutame mõnda minu arvates olulist varianti gcc.

Variant -I tee / kataloog / kataloog / koos päiste / failidega - lisab määratud kataloogi päisefailide otsinguteede loendisse. Valiku lisatud kataloog -Mina kõigepealt otsiti, seejärel jätkub otsing tavapärastes süsteemikataloogides. Kui valikud -Mina skaneeritakse mitu nende poolt määratud kataloogi vasakult paremale, kui valikud ilmuvad.

Valik -Sein - kuvab koodis võimalike tõrgete põhjustatud hoiatused, mis ei takista programmi kompileerimist, kuid mis võib kompilaatori arvates selle täitmisel tekitada teatavaid probleeme. Oluline ja kasulik võimalus, arendajad gcc soovitage seda alati kasutada. Näiteks antakse järgmise faili kompileerimisel palju hoiatusi:

1 / * remark.c * /
2
3 staatiline int k \u003d 0;
4 staatiline int l ( int a);
5
6 peamist ()
7 {
8
9 int a;
10
11 int b, c;
12
13 b + 1;
14
15 b \u003d c;
16
17 int * p;
18
19 b \u003d * p;
20
21 }


$ gcc -o märkus remark.c
$ gcc -Wall - märkuse remark.c lisamine
remark.c: 7: hoiatus: tagasitüübi vaikeseadeks on int

remark.c: 13: hoiatus: avaldus, millel puudub mõju
remark.c: 9: hoiatus: kasutamata muutuja 'a'
remark.c: 21: hoiatus: kontroll jõuab tühja funktsiooni lõppu
remark.c: tipptasemel:
remark.c: 3: hoiatus: 'k' on määratletud, kuid mitte kasutatud
remark.c: 4: hoiatus: „l” kuulutatakse staatiliseks, kuid pole kunagi määratletud
remark.c: funktsioonis „main”:
remark.c: 15: hoiatus: selles funktsioonis kasutatakse tähist c initsialiseerimata
remark.c: 19: hoiatus: selles funktsioonis kasutatakse algatuseta tähist p

Valik - viga - muudab kõik hoiatused vigadeks. Hoiatuse ilmumisel katkestab koostamisprotsessi. Kasutatakse koos variant -Sein.

$ gcc -Werror -o märkus remark.c
$ gcc -Werror -Wall -o remark.c märkuse lisamine
cc1: hoiatusi käsitletakse vigadena
remark.c: 7: tõrge: tagastamise tüüp vaikimisi väärtus "int"
remark.c: funktsioonis „main”:
remark.c: 13: viga: avaldus, millel pole mõju
remark.c: 9: tõrge: kasutamata muutuja 'a'

Valik -g - paigutab siluri tööks vajaliku teabe objekti või käivitatavasse faili gdb... Järgnevaks silumiseks projekti koostamisel variant -g tuleb lisada nii kompileerimise ajal kui ka linkimise ajal.

Valikud -O1, -O2, -O3 - määrake kompilaatori loodud koodi optimeerimise tase. Arvu kasvades optimeerimise aste suureneb. Valikute toimimist saab näha sellest näitest.

Algne fail:

/ * ring.c * /

Peamine ( tühine )
{

int i;

jaoks (i \u003d 0; i< 10 ; ++i)
;

tagasi i;

Kompileerimine vaikimisi optimeerimise tasemega:

$ gcc -S ring.c
$ vähem ringi.s
.fail "ring.c"
.tekst
.globl peamine
.tüüp peamine, @funktsioon
peamine:
pushl% ebp
movl% esp,% ebp
subl 16 dollarit,% esp
movl 0 dollarit, -4 (% ebp)
jmp .L2
.L3:
addl $ 1, -4 (% ebp)
.L2:
cmpl 9 dollarit, -4 (% ebp)
jle .L3
movl -4 (% ebp),% eax
lahkuda
ret
.suurus peamine, .- peamine
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.sektsioon .note.GNU-stack, "", @ progbits

Kompileerimine maksimaalse optimeerimistasemega:

$ gcc -S -O3 ring.c
$ vähem ringi.s
.fail "ring.c"
.tekst
.p2joon 4.15
.globl peamine
.tüüp peamine, @funktsioon
peamine:
pushl% ebp
movl 10 dollarit, eax%
movl% esp,% ebp
popl% ebp
ret
.suurus peamine, .- peamine
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.sektsioon .note.GNU-stack, "", @ progbits

Teisel juhul puudub saadud koodil isegi vihje ühegi silmuse kohta. I väärtust saab arvutada koostamisetapis, mis tehti.

Paraku pole reaalsete projektide puhul erinevusi optimeerimise erinevatel tasemetel praktiliselt märgatav ...

Variant -00 - tühistab koodi optimeerimise. See suvand on vajalik rakenduse silumise etapis. Nagu ülalpool näidatud, võib optimeerimine viia programmi struktuuris tundmatuseni muutumiseni, käivitatava ja lähtekoodi vaheline seos ei ole selge ja vastavalt sellele pole programmi sammhaaval silumine võimalik. Kui suvand on lubatud -g, on soovitatav lisada ja -O0.

Optsioon -Os - seab optimeerimise mitte koodi tõhususe, vaid saadud faili suuruse järgi. Sel juhul peaks programmi jõudlus olema võrreldav vaikimisi optimeerimistasemega kompileerimise käigus saadud koodi jõudlusega.

Valik -march \u003d arhitektuur - täpsustab sihtprotsessori arhitektuuri. Toetatavate arhitektuuride loend on näiteks protsessorpere jaoks ulatuslik Intel / AMD sa võid küsida i386, pentium, prescott, opteron-sse3 jne. Binaarsete jaotuste kasutajad peaksid meeles pidama, et programmid töötaksid määratud valikuga korrektselt, soovitav, et kõik kaasatud teegid kompileeritaks sama valikuga.

Linkerile edastatud valikuid arutatakse allpool.

Väike lisandus:

Seda öeldi eespool gcc määrab ülekantud failide tüübi (programmeerimiskeele) nende laiendi järgi ja teeb vastavalt arvatavale tüübile (keelele) nendega toiminguid. Kasutaja on kohustatud jälgima loodud failide laiendusi, valides need vastavalt lepingule gcc... Reaalsuses gcc saate libistada suvaliste nimedega faile. Gcc -x variant võimaldab teil täpselt määratleda kompileeritud failide programmeerimiskeele. See suvand kehtib kõigi järgmiste käsus loetletud failide kohta (kuni ilmub järgmine suvand -x). Võimalikud valikuargumendid:

c c-header c-cpp-output

c ++ c ++ - päis c ++ - cpp-output

objektiiv-c eesmärk-c-päis eesmärk-c-cpp-väljund

objektiiv-c ++ eesmärk-c ++ - päis eesmärk-c ++ - cpp-väljund

monteerija monteerija-cpp-ga

ada

f77 f77-cpp-sisend

f95 f95-cpp-sisend

java

Argumentide eesmärk peaks olema selge nende kirjutamisest (siin cpp pole midagi pistmist C ++, see on eeltöötleja poolt eeltöödeldud lähtekoodifail). Kontrollime:

$ mv hello.c hello.txt
$ gcc -Wall -x c -o tere hello.txt
$ ./hello
Tere, Maailm

Eraldi koostamine

Keelte tugevus C / C ++ on võimalus jagada programmi lähtekood mitmeks failiks. Veel võib öelda - eraldi kompileerimise võimalus on keele alus, ilma selle tõhusa kasutamiseta C pole mõeldav. See on mitme failiga programmeerimine, mis võimaldab teil seda sisse viia C sellised suured projektid nagu Linux (siin sõna all Linux tähendab nii kernelit kui ka süsteemi tervikuna). Mida annab eraldi kompileerimine programmeerijale?

1. Võimaldab muuta programmi (projekti) koodi loetavamaks. Mitmekümne ekraani lähtefail muutub peaaegu üle jõu. Kui jagate selle vastavalt mõnele (eelmõeldud) loogikale mitmeks väikeseks killuks (igaüks eraldi failina), on projekti keerukusega palju lihtsam toime tulla.

2. Lühendab projekti uuesti kompileerimise aega. Kui muudatused tehakse ühes failis, pole mõtet kogu projekti ümber kompileerida, piisab ainult selle muudetud faili uuesti kompileerimisest.

3. Võimaldab jagada projekti tööd mitme arendaja vahel. Iga programmeerija loob oma projekti osa ja silub seda, kuid igal ajal on võimalik kogu sellest tulenev arendus koguda (ümber ehitada) lõpptooteks.

4. Ilma eraldi kompileerimiseta poleks raamatukogusid. Koodi korduskasutamine ja levitamine veebisaidil C / C ++, ja kood on binaarne, mis võimaldab ühelt poolt pakkuda arendajatele lihtsat mehhanismi selle kaasamiseks oma programmidesse, teiselt poolt varjata nende eest konkreetseid rakenduse üksikasju. Kas projekti kallal töötades tasub alati mõelda ja mitte vajada midagi sellest, mis on millalgi juba tehtud? Võib-olla peaksite osa koodist eelnevalt raamatukoguks valima ja korrastama? Minu arvates lihtsustab selline lähenemine elu oluliselt ja säästab palju aega.

Gccmuidugi toetab eraldi kompileerimist ega nõua kasutajalt mingeid erijuhiseid. Üldiselt on kõik väga lihtne.

Siin on praktiline näide (ehkki väga, väga tinglik).

Lähtekoodi faili komplekt:

/ * main.c * /

# kaasata

# sisaldab "esimene.h"
# sisaldab "teine.h"

int peamine ( tühine )
{

Esimene ();
teine \u200b\u200b();

Printf ("Põhifunktsioon ... \\ n");

tagasi 0 ;


/ * esimene.h * /

tühine esimene ( tühine );


/ * esimene.c * /

# kaasata

# sisaldab "esimene.h"

tühine esimene ( tühine )
{

Printf ("Esimene funktsioon ... \\ n");


/ * teine.h * /

tühine teine \u200b\u200b( tühine );


/ * teine.c * /

# kaasata

# sisaldab "teine.h"

tühine teine \u200b\u200b( tühine )
{

Printf ("Teine funktsioon ... \\ n");

Üldiselt on meil see:

$ ls
esimene.c esimene.h peamine.c teine.c teine.h

Kogu selle majanduse saab koondada ühte käsku:

$ gcc -Wall -o main main.c esimene.c teine.c
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Ainult see ei anna meile praktiliselt mingeid boonuseid, ja jaotatud mitme faili peale, välja arvatud struktureeritum ja loetavam kood. Sellise koostamise lähenemisviisi korral ilmnevad kõik ülaltoodud eelised:

$ gcc -Wall -c main.c
$ gcc -Wall -c first.c
$ gcc -Wall -c sekund.c
$ ls
esimene.c esimene.h esimene.o main.c main.o teine.c teine.h teine.o
$ gcc -o peamine main.o esimene.o teine.o
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Mida me teinud oleme? Igast lähtefailist (kompileerimine valikuga -c) sai objekti faili. Seejärel ühendati objektfailid lõplikuks käivitatavaks. Muidugi meeskonnad gcc neid on rohkem, kuid keegi ei kogu projekte käsitsi, selleks on olemas kogujakommunikatsiooniteenused (kõige populaarsemad tegema). Kõik ülaltoodud eraldi kompileerimise eelised ilmnevad kogumisutiliitide abil.

Tekib küsimus: kuidas linker õnnestub objektifaile kokku panna, õigesti arvutades kõnede aadressi? Kuidas ta isegi teab, et fail second.o sisaldab teise () funktsiooni koodi ja faili main.o kood sisaldab selle üleskutset? Selgub, et kõik on lihtne - objektifail sisaldab nn sümbolitabel , sealhulgas mõne koodipositsiooni nimed (funktsioonid ja välised muutujad). Linker skannib iga objektifaili sümbolitabeli, otsib tavalisi (koos sobivate nimedega) positsioone, mille põhjal teeb järeldused kasutatud funktsioonide (või andmeplokkide) koodi tegeliku asukoha kohta ja arvutab vastavalt sellele ümber käivitatavas failis olevad kõneaadressid.

Sümbolitabelit saate vaadata utiliidi abil nm.

USD nm main.o
U kõigepealt
00000000 T peamine
U paneb
U teine
Esiteks $ nm
00000000 T esimene
U paneb
USD nm teine.o
U paneb
00000000 T sekundit

Put-kõne välimust seletatakse standardse teegi funktsiooni printf () kasutamisega, mis kompileerimise ajal muutus put () -ks.

Sümbolitabel pole kirjutatud mitte ainult objektfaili, vaid ka käivitatavasse faili:

$ nm peamine
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484fc R _IO_stdin_used
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0c d __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048538 r __FRAME_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
080484b0 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
0804a010 D __dso_handle
w __gmon_start__
080484aa T __i686.get_pc_thunk.bx
08049f0c d __init_array_end
08049f0c d __init_array_start
08048440 T __libc_csu_fini
08048450 T __libc_csu_init
U [e-posti aadress on kaitstud]@ GLIBC_2.0
0804a014 A _edata
0804a01c A _end
080484dc T _fini
080484f8 R _fp_hw
080482b8 T _init
08048330 T _start
0804a014 b valmis, 7021
0804a00c W data_start
0804a018 b dtor_idx.7023
0804840c T esimene
080483c0 t frame_dummy
080483e4 T peamine
U [e-posti aadress on kaitstud]@ GLIBC_2.0
08048420 T teine

Sümbolitabeli kaasamine käivitatavasse on silumise hõlbustamiseks eriti vajalik. Põhimõtteliselt pole rakenduse käitamiseks tegelikult vaja. Reaalsete programmide käivitatavate failide jaoks, millel on palju funktsioonimääratlusi ja väliseid muutujaid, kasutades hunnikut erinevaid raamatukogusid, muutub sümbolitabel üsna ulatuslikuks. Väljundfaili suuruse vähendamiseks saab selle eemaldada, kasutades valikuga gcc -s.

$ gcc -s -o peamine main.o esimene.o teine.o
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...
$ nm peamine
nm: peamine: sümboliteta

Tuleb märkida, et linkimise ajal linker funktsioonikõne konteksti ei kontrolli, ta ei jälgi ei tagastamisväärtuse tüüpi ega aktsepteeritud parameetrite tüüpi ega arvu (ning tal pole kohta sellist teavet hankida). Kõik kõne valideerimine tuleb teha kompileerimise ajal. Mitme failiga programmeerimise puhul on selleks vaja kasutada keele päisefailide mehhanismi C.

Raamatukogud

Raamatukogu - keeles C, fail, mis sisaldab objekti koodi, mille saab linkimise ajal teegi abil programmiga siduda. Tegelikult on raamatukogu objektide failide kogum, mis on lingitud erilisel viisil.

Raamatukogude eesmärk on pakkuda programmeerijale koodi taaskasutamise standardset mehhanismi, mis on lihtne ja usaldusväärne.

Operatsioonisüsteemi ja rakendustarkvara seisukohast on raamatukogud staatiline ja jagatud (dünaamiline ).

Staatiline raamatukogu kood sisaldub käivitatavas failis viimase linkimisel. Teek osutub failina "juhtmega", teegi kood "ühendatakse" ülejäänud failikoodiga. Staatilisi raamatukogusid kasutav programm muutub iseseisvaks ja seda saab käivitada peaaegu igas sobiva arhitektuuri ja opsüsteemiga arvutis.

Jagatud teegi kood laaditakse ja ühendatakse opsüsteemi poolt programmi koodiga programmi taotlusel selle täitmise ajal. Dünaamiline teegi kood ei sisaldu programmi käivitatavas failis, vaid käivitatavasse faili on lisatud ainult teegi link. Selle tulemusel lakkab jagatud teeke kasutav programm olema autonoomne ja seda saab edukalt käivitada ainult süsteemis, kuhu asjaomased teegid on installitud.

Ühisel raamatukogu paradigmal on kolm olulist eelist:

1. Käivitatava faili maht on oluliselt vähenenud. Süsteemis, mis sisaldab paljusid sama koodi sisaldavaid binaare, pole vaja iga käivitatava koodi koopiat säilitada.

2. Mitme rakenduse kasutatav jagatud teegi kood salvestatakse RAM-i ühes eksemplaris (tegelikult pole kõik nii lihtne ...), mille tulemusel väheneb süsteemi vajadus saadaoleva RAM-i järele.

3. Iga ühise käivitatava faili koodimuudatuste korral pole iga käivitatavat faili vaja uuesti üles ehitada. Dünaamilise teegi koodi muudatused ja parandused kajastuvad automaatselt igas seda kasutavas programmis.

Ilma jagatud teegi paradigmata poleks eelkompileeritud (binaarseid) jaotusi Linux (jah, ükskõik mida ei eksisteerinud). Kujutage ette jaotuse suurust, mille iga binaarne sisaldaks standarditeegi koodi C (ja kõik muud kaasatud raamatukogud). Kujutage vaid ette, mida oleks vaja süsteemi värskendamiseks pärast ühe laialt kasutatava raamatukogu kriitilise haavatavuse kindlakstegemist ...

Nüüd väike praktika.

Kasutame illustreerimiseks eelmise näite lähtefailide komplekti. Esimese () ja teise () funktsiooni koodi (teostuse) paneme omatehtud raamatukokku.

Linuxis võetakse vastu järgmine raamatukogufailide nimetamisskeem (ehkki seda ei täheldata alati) - teegi failinimi algab libi eesliitega, millele järgneb teegi nimi, lõpus laiend .a ( arhiiv ) - staatilise raamatukogu jaoks, .so ( jagatud objekt ) - jagatud (dünaamilise) korral loetletakse pärast laiendamist versiooninumbrid punkti kaudu (ainult dünaamiliste raamatukogude jaoks). Päisefailide kogule vastav nimi (jällegi tavaliselt) koosneb teegi nimest (ilma eesliite ja versioonita) ja laiendist .h. Näiteks: libogg.a, libogg.so.0.7.0, ogg.h.

Esiteks loogem ja kasutage staatilist teeki.

Esimene () ja teine \u200b\u200b() funktsioon koostavad meie libhello teegi sisu. Teekifaili nimi on vastavalt libhello.a. Võrdleme päisefaili hello.h raamatukoguga.

/ * tere.h * /

tühine esimene ( tühine );
tühine teine \u200b\u200b( tühine );

Muidugi, read:

# sisaldab "esimene.h"


# sisaldab "teine.h"

failides main.c, first.c ja second.c on vaja asendada järgmistega:

# sisaldab "tere.h"

Nüüd sisestame järgmise käskude jada:

$ gcc -Wall -c first.c
$ gcc -Wall -c sekund.c
$ ar crs libhello.a esimene.o teine.o
$ fail libhello.a
libhello.a: praegune arhiiv

Nagu juba mainitud, on raamatukogu objektfailide kogum. Kahe esimese käsklusega lõime need objektfailid.

Järgmisena peate linkima objektfailid komplekti. Selleks kasutatakse arhiveerijat ar - utiliit "liimib" mitu faili ühte, tulemuseks olev arhiiv sisaldab iga üksiku faili taastamiseks (väljavõtmiseks) vajalikku teavet (sealhulgas selle omandiõiguse, juurdepääsu, aja atribuudid). Arhiivi sisu mis tahes "tihendamist" või muude salvestatud andmete teisendamist ei teostata.

C arname variant - arhiivi loomine, kui nimega arhiivi ei eksisteeri, luuakse see, vastasel juhul lisatakse failid olemasolevasse arhiivi.

Variant r - seab arhiivi värskendusrežiimi. Kui määratud nimega fail on arhiivis juba olemas, kustutatakse see ja uus fail lisatakse arhiivi lõppu.

Variant s - lisab (värskendab) arhiivi indeksi. Sel juhul on arhiiviindeks tabel, milles iga arhiveeritud failides määratletud sümboolse nime (funktsiooni või andmeploki nime) jaoks on vastav objektifaili nimi seotud. Arhiiviindeks on vajalik raamatukoguga töö kiirendamiseks - vajaliku definitsiooni leidmiseks pole vaja kõigi arhiivifailide sümbolitabelit läbi vaadata, võite minna otse soovitud nime sisaldava faili juurde. Arhiivide registrit saate vaadata juba tuttava utiliidi abil nm kasutades seda valikuga -s (kuvatakse ka kõigi arhiivi objektifailide sümboltabelid):

$ nm -s libhello.a
Arhiivi register:
esimesena esimeses
teine \u200b\u200bsekundis.o

esimene.o:
00000000 T esimene
U paneb

teine.o:
U paneb
00000000 T sekundit

Arhiiviindeksi loomiseks on spetsiaalne utiliit ranlib... Raamatukogu libhello.a oleks võinud luua nii:

$ ar cr libhello.a esimene.o teine.o
$ ranlib libhello.a

Ilma arhiiviindeksita töötab raamatukogu siiski hästi.

Kasutagem nüüd meie teeki:

$ gcc -Wall -c main.c
$
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Töötab ...

Noh nüüd kommentaarid ... On kaks uut võimalust gcc:

Valiku -l nimi - linkerile edastatud, näitab vajadust ühendada libnameekide teek käivitatava failiga. Ühendamiseks tähendab, et need ja sellised funktsioonid (välised muutujad) on sellises ja sellises teegis määratletud. Meie näites on raamatukogu staatiline, kõik sümboolsed nimed viitavad koodile, mis asub otse käivitatavas failis. Pöörake tähelepanu võimalustele -l teegi nimi on määratletud nimega ilma libli eesliiteta.

Valik -L / tee / kataloog / kataloog / koos / teekidega - linkerile edastatud, määrab lingitud teeke sisaldava kataloogi tee. Meie puhul mõte . , otsib linker kõigepealt teeke praegusest kataloogist, seejärel süsteemis määratletud kataloogidest.

Siinkohal tuleks teha väike märkus. Fakt on see, et paljude võimaluste puhul gcc oluline on nende käsureal kuvamise järjekord. Nii otsib linker koodi, mis vastab failisümbolitabelis täpsustatud nimedele käsureal loetletud raamatukogudes. pärast selle faili nimi. Linker ignoreerib failinime ees loetletud teekide sisu:

$ gcc -Wall -c main.c
$ gcc -o main -L. -lhello main.o
main.o: Funktsioonis "main":
main.c :(. tekst + 0xa): määratlemata viide esimesele
main.c :(. tekst + 0xf): määratlemata viide "teisele"

$ gcc -o peamine main.o -L. -hello
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

See käitumine gcc tulenevalt arendajate soovist pakkuda kasutajale võimalust ühendada faile raamatukogudega erineval viisil, kasutada ristuvaid nimesid ... Minu arvates on parem mitte sellega vaevata. Üldiselt tuleb lingitud teegid loetleda neid viitava faili nime järel.

Teekide asukoha määramiseks süsteemis on alternatiivne viis. Sõltuvalt jaotusest võib keskkonnamuutuja LD_LIBRARY_PATH või LIBRARY_PATH salvestada koolonitega eraldatud kataloogide loendit, milles linker peaks otsima raamatukogusid. Reeglina pole seda muutujat vaikimisi määratletud, kuid selle loomist ei takista miski:

$ echo $ LD_LIBRARY_PATH

/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../i686-pc-linux-gnu/bin/ld: ei leia -lhello
colle2: ld täitmine väljus tagasitulekukoodiga 1
$ eksport LIBRARY_PATH \u003d.
$ gcc -o main main.o -lhello
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Keskkonnamuutujatega manipuleerimine on kasulik nii oma raamatukogude loomisel kui ka silumisel, aga ka juhul, kui peate rakendusega ühendama mõne mittestandardse (vananenud, värskendatud, muudetud - üldiselt erinevad jaotuses sisalduvast) jagatud teegi.

Nüüd loome ja kasutame dünaamilist teeki.

Algsete failide komplekt jääb samaks. Sisestame käsud, vaatame, mis juhtus, lugege kommentaare:

$ gcc -Wall -fPIC -c first.c
$ gcc -Wall -fPIC -c second.c
$ gcc-Shared -o libhello.so.2.4.0.5 -Wl, -soname, libhello.so.2 first.o second.o

Mida sa selle tulemusel said?

$ -fail libhello.so.2.4.0.5
libhello.so.2.4.0.5: ELF-i 64-bitine LSB jagatud objekt, x86-64, versioon 1 (SYSV), dünaamiliselt lingitud, eemaldamata

Fail libhello.so.2.4.0.5 on meie jagatud teek. Sellest, kuidas seda kasutada, räägime allpool.

Nüüd kommentaarid:

Funktsioon -fPIC - nõuab objektfailide loomisel kompilaatori genereerimist positsioonist sõltumatu kood (PIC - positsioonist sõltumatu kood ), on selle peamiseks erinevuseks aadresside esitusviis. Fikseeritud (staatiliste) positsioonide täpsustamise asemel arvutatakse kõik aadressid punktis b täpsustatud nihke põhjal globaalne nihetabel (globaalne nihetabel - GOT ). Positsioonist sõltumatu koodivorming võimaldab ühendada käivitatavad moodulid põhiprogrammi koodiga selle laadimise ajal. Sellest lähtuvalt on positsioonist sõltumatu koodi peamine eesmärk dünaamiliste (jagatud) teekide loomine.

Jagatud variant - näitab gccet tulemus ei peaks olema mitte käivitatav fail, vaid jagatud objekt - dünaamiline teek.

Valik -Wl, -nimi, libhello.so.2 - komplektid soname raamatukogud. Sonaamist räägime üksikasjalikult järgmises lõigus. Nüüd arutame selle valiku vormingut. Esmapilgul näib kummaline, et komadega konstrueerimine on ette nähtud kasutaja otseseks suhtlemiseks linkeriga. Kompileerimise ajal gcc kutsub linkerit automaatselt, automaatselt, oma äranägemise järgi, gcc läbib töö edukaks täitmiseks vajalikud võimalused. Kui kasutajal on vaja linkimisprotsessi ise sekkuda, saab ta kasutada spetsiaalset võimalust gcc -Wl, -valik, väärtus1, väärtus2 ...... Mida tähendab linkerile ülekandmine ( -Wl) valik -valik argumentidega väärtus1, väärtus2 jne. Meie puhul anti võimalus linkerile üle -soname argumendiga libhello.so.2.

Nüüd soname kohta. Teekide loomisel ja levitamisel on probleeme ühilduvuse ja versioonikontrolliga. Selleks, et süsteemil, eriti dünaamilisel raamatukogu laaduril, oleks ettekujutus sellest, millist raamatukogu versiooni rakenduse koostamisel kasutati ja mis seetõttu on selle edukaks toimimiseks vajalik, pakuti spetsiaalset identifikaatorit - soname , mis on paigutatud nii teegi enda kui ka rakenduse käivitatavasse faili. Sonüümitunnus on string, mis sisaldab raamatukogu nime, millele on lisatud eesliide lib, dot, laiend, seega jälle punkt ja teegi versiooni üks või kaks (punktiga eraldatud) numbrit - lib name .so. x. y. See tähendab, et soname sobib teegi failinimega versiooninumbri esimese või teise numbrini. Olgu meie raamatukogu käivitatava faili nimi libhello.so.2.4.0.5, siis võib teegi sonaam olla libhello.so.2. Raamatukogu liidese muutmisel tuleb muuta selle soname! Mis tahes koodimuudatustega, mis põhjustavad kokkusobimatuse varasemate väljalasketega, tuleb lisada uus sonaam.

Kuidas see kõik töötab? Oletame, et mõne rakenduse edukaks täitmiseks on vajalik teek nimega tere, oletagem, et süsteemis on üks, raamatukogu faili nimi on libhello.so.2.4.0.5 ja sinna sisse kirjutatud teegi libhello.so.2 nimi. Taotluse koostamise etapis linker vastavalt võimalusele - Tere!, otsib süsteemist faili nimega libhello.so. Reaalses süsteemis on libhello.so sümboolne link saidile libhello.so.2.4.0.5. Olles saanud juurdepääsu teegi failile, loeb linker sinna kirjutatud sonaami väärtuse ja paigutab selle muu hulgas rakenduse käivitatavasse faili. Kui rakendus käivitatakse, saab dünaamiline raamatukogulaadur taotluse lisada raamatukogu koos käivitatavast failist loetud sonaamiga ja proovib süsteemist leida teeki, mille failinimi vastab sonaamile. See tähendab, et laadur proovib leida faili libhello.so.2. Kui süsteem on õigesti konfigureeritud, peaks see sisaldama sümboolset linki libhello.so.2 failile libhello.so.2.4.0.5, laadija pääseb vajalikku teeki ja siis ühendab ta kõhklemata (ja ilma midagi muud kontrollimata) selle rakendusega. Kujutame nüüd ette, et oleme kolinud sel viisil kompileeritud rakenduse teise süsteemi, kus juurutatakse ainult soname libhello.so.1 teegi eelmist versiooni. Programmi käitamise proovimisel ilmneb tõrge, kuna selles süsteemis pole ühtegi faili nimega libhello.so.2.

Seega peab linker pakkumise koostamise etapis pakkuma teegifaili (või teegifaili sümboolse lingi) nimega lib-nimi .so: laadur vajab käitustõmmise ajal faili (või sümboolset linki) nimega lib-nimi .so. x. y. Mida nimi lib nimega .so. x. y peab vastama kasutatava teegi sonaamistringile.

Binaarsete jaotuste korral paigutatakse raamatukogufail libhello.so.2.4.0.5 ja link sellele libhello.so.2 libhello paketti ning link libhello.so, mis on vajalik ainult kompileerimiseks, koos hello.h teegi päisefailiga pakitud libhello-devel paketti (devel pakett sisaldab ka libhello.a teegi staatilise versiooni faili, staatilist teeki saab kasutada, ka ainult kompileerimisetapis). Paketi lahti pakkimisel asuvad kõik loetletud failid ja lingid (va hello.h) ühes kataloogis.

Veendugem, et antud sonaamirida oleks tegelikult meie raamatukogu failis kirjas. Kasutagem mega utiliiti objdump koos võimalusega -p :

$ objdump -p libhello.so.2.4.0.5 | grep SONAME
SONAME libhello.so.2


Utiliit objdump on võimas tööriist, mis võimaldab teil saada põhjalikku teavet objekti või käivitatava faili sisemise sisu (ja seadme) kohta. Umbes mehe leht ütleb seda objdump esiteks on see kasulik programmeerijatele, kes loovad silumis- ja kompileerimisriistu, mitte ei kirjuta lihtsalt suvalisi rakendusprogramme :) Eelkõige koos võimalusega -d see on lahtivõtja. Kasutasime varianti -p - kuvada mitmesugust metafaili objektifaili kohta.

Selles raamatukogu loomise näites järgisime järeleandmatult eraldi kompileerimise põhimõtteid. Muidugi võiks raamatukogu moodustada niimoodi, ühe kõnega gcc:

$ gcc -jagatud -sein -fPIC -o libhello.so.2.4.0.5 -Wl, -nimi, libhello.so.2 esimene.c teine.c

Proovime nüüd kasutada saadud teeki:

$ gcc -Wall -c main.c
$
/ usr / bin / ld: ei leia -hello
colle2: ld tagastab 1 väljumise oleku

Linker vannub. Pidage meeles, mida eespool öeldi sümboolsete linkide kohta. Looge libhello.so ja proovige uuesti:

$ ln -s libhello.so.2.4.0.5 libhello.so
$ gcc -o peamine main.o -L. -lhello -Wl, -rpath ,.

Nüüd on kõik rahul. Käivitame loodud binaari:

Viga ... Laadur kirub, ei leia teeki libhello.so.2. Veendugem, et link saidile libhello.so.2 on tõesti käivitatavas failis kirjas:

$ objdump -p main | grep VAJALIK
VAJALIK libhello.so.2
VAJALIK libc.so.6

$ ln -s libhello.so.2.4.0.5 libhello.so.2
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

See töötas ... Kommenteerib nüüd uusi võimalusi gcc.

Valik -Wl, -patra,. - juba tuttav konstruktsioon, andke võimalus linkerile üle -tee argumendiga . ... Läbi -tee saate programmi käivitatavasse faili kirjutada täiendavaid teid, mööda mida jagatud teegilaadur raamatukogufaile otsib. Meie puhul on tee registreeritud . - teegi failide otsimine algab aktiivsest kataloogist.

$ objdump -p main | grep RPATH
RPATH.

Tänu sellele suvandile pole programmi käivitamisel vaja keskkonnamuutujaid muuta. On selge, et kui teisaldate programmi mõnda teise kataloogi ja proovite seda käivitada, siis teegi faili ei leita ja laadur annab veateate:

$ mv peamine ..
$ ../main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Samuti saate utiliidi abil teada saada, milliseid jagatud teeke rakendus vajab ldd:

$ ldd peamine
linux-vdso.so.1 \u003d\u003e (0x00007fffaddff000)
libhello.so.2 \u003d\u003e ./libhello.so.2 (0x00007f9689001000)
libc.so.6 \u003d\u003e /lib/libc.so.6 (0x00007f9688c62000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9689205000)

Väljundis ldd iga nõutava teegi jaoks täpsustatakse selle sonaam ja kogu tee raamatukogu faili juurde, mis määratakse kindlaks vastavalt süsteemi sätetele.

Nüüd on aeg rääkida sellest, kuhu süsteem peaks teegi failid paigutama, kuhu laadija proovib neid leida ja kuidas seda protsessi hallata.

Vastavalt kokkulepetele FHS (failisüsteemi hierarhia standard) süsteemil peab raamatukogufailide hoidmiseks olema kaks (vähemalt) kataloogi:

/ lib - siin kogutakse peamised jaotusraamatukogud, mis on vajalikud programmide jaoks kataloogist / bin ja / sbin tööle;

/ usr / lib - siin hoitakse teeke, mida vajavad rakendusprogrammid kataloogidest / usr / bin ja / usr / sbin;

Teekidele vastavad päisefailid peaksid asuma kataloogis / usr / include.

Laadur otsib vaikimisi nendest kataloogidest teegi faile.

Lisaks ülalloetletutele peab süsteem sisaldama kataloogi / usr / local / lib - seal peavad olema ka teegid, mille kasutaja on iseseisvalt juurutanud, mööda minnes paketihaldussüsteemist (ei kuulu komplekti). Näiteks selles kataloogis on vaikimisi allikatest koostatud teegid (allikatest installitud programmid asuvad kataloogides / usr / local / bin ja / usr / local / sbin, muidugi räägime binaarsetest jaotustest). Sel juhul paigutatakse raamatukogu päised kataloogi / usr / local / include.

Mitmes jaotuses (tuumaühikutes) Ubuntu) laadur ei ole konfigureeritud kataloogi / usr / local / lib sirvimiseks, seega kui kasutaja installib teegi allikatest, ei näe süsteem seda. Seda teevad spetsiaalselt turustuskomplekti autorid, et õpetada kasutajat tarkvara installima ainult paketihaldussüsteemi kaudu. Allpool kirjeldatakse, kuidas sellisel juhul toimida.

Tegelikult ei vaata laadur teegi failide leidmise protsessi lihtsustamiseks ja kiirendamiseks ülaltoodud katalooge iga kord, kui sellele juurde pääseb, vaid tugineb andmebaasis, mis on salvestatud faili /etc/ld.so.cache (teegi vahemälu). See sisaldab teavet selle kohta, kus antud sonamele vastav raamatukogu fail süsteemis asub. Pärast seda, kui laadur on saanud konkreetse rakenduse jaoks vajalike teekide loendi (programmi käivitatavas failis täpsustatud sonaamiteegide loend), kasutab /etc/ld.so.cache iga vajaliku teegi faili juurde jõudmiseks tee tee mällu laadimiseks. Lisaks saab laadur vaadata katalooge, mis on loetletud süsteemimuutujates LD_LIBRARY_PATH, LIBRARY_PATH ja käivitatava faili väljal RPATH (vt ülal).

Teekide vahemälu haldamiseks ja ajakohasena hoidmiseks kasutatakse utiliiti ldconfig... Kui joosta ldconfig ilma võimalike suvanditeta skannib programm käsuribal määratud katalooge, usaldusväärseid katalooge / lib ja / usr / lib, faile /etc/ld.so.conf loetletud katalooge. Iga määratud kataloogides asuva raamatukogufaili jaoks loetakse sonaame, luuakse sonaamil põhinev sümboolne link, värskendatakse /etc/ld.so.cache teavet.

Veendugem järgmises:

$ ls
tere.h libhello.so libhello.so.2.4.0.5 main.c
$
$ sudo ldconfig / full / path / to / kataogu / c / example
$ ls
tere.h libhello.so libhello.so.2 libhello.so.2.4.0.5 main main.c
$ ./main
Esimene funktsioon ...
Teine funktsioon ...
Põhifunktsioon ...

Esimene kõne ldconfig lisasime oma raamatukogu vahemällu, välistasime selle teise kõnega. Pange tähele, et peamise kompileerimisel jäeti see valik tegemata -Wl, -rpath ,.tulemusena otsis laadur vajalikke teeke ainult vahemälust.

Nüüd peaks olema selge, mida teha, kui pärast teegi installimist lähteallikast süsteem seda ei näe. Kõigepealt peate sisestama kogu tee kataloog koos teegi failidega (vaikimisi / usr / local / lib) faili /etc/ld.so.conf. Formaat /etc/ld.so.conf - fail sisaldab kataloogide loendit, eraldatud kooloniga, tühiku, vahekaardi või uue reaga, kust otsida raamatukogusid. Siis helistage ldconfig ilma võimalusteta, kuid superkasutaja õigustega. Kõik peaks toimima.

Noh, lõpuks räägime sellest, kuidas raamatukogude staatilised ja dünaamilised versioonid eksisteerivad koos. Mis on tegelik küsimus? Eespool, kui arutati teegi failide aktsepteeritud nimede ja asukohtade üle, öeldi, et teegi staatiliste ja dünaamiliste versioonide faile hoitakse samas kataloogis. Kuidas gcc saab teada, millist raamatukogu me soovime kasutada? Vaikimisi eelistatakse dünaamilist teeki. Kui linker leiab dünaamilise teegi faili, siis ei kõhkle see linkimast programmi käivitatava failiga:

$ ls
tere.h libhello.a libhello.so libhello.so.2 libhello.so.2.4.0.5 main.c
$ gcc -Wall -c main.c
$ gcc -o peamine main.o -L. -lhello -Wl, -rpath ,.
$ ldd peamine
linux-vdso.so.1 \u003d\u003e (0x00007fffe1bb0000)
libhello.so.2 \u003d\u003e ./libhello.so.2 (0x00007fd50370b000)
libc.so.6 \u003d\u003e /lib/libc.so.6 (0x00007fd50336c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd50390f000)
$ du-h peamine
12K peamine

Pöörake tähelepanu käivitatava programmi suurusele. See on väikseim võimalik. Kõik kasutatavad teegid on dünaamiliselt ühendatud.

Olemas gcc -staatiline variant - linkerile juhendamine kasutama kõigi rakenduse jaoks vajalike teekide ainult staatilisi versioone:

$ gcc -staatiline -o peamine main.o -L. -hello
$ faili peamine
peamine: ELF-i 64-bitine käivitatav LSB, x86-64, versioon 1 (GNU / Linux), staatiliselt lingitud, GNU / Linuxile 2.6.15, eemaldamata
$ ldd peamine
pole dünaamiline käivitatav
$ du-h peamine
Põhiline 728K

Käivitatava faili maht on 60 korda suurem kui eelmises näites - faili on lisatud standardsed keeleteegid C... Nüüd saab meie rakendust turvaliselt kataloogist kataloogi ja isegi teistesse masinatesse üle kanda, teekide raamatukogu kood on faili sees, programm on täiesti autonoomne.

Mis siis, kui peate statistiliselt linkima ainult osa kasutatud teekidest? Võimalik variant lahendused - tehke teegi staatilise versiooni nimi jagatud nimest erinevaks ja rakenduse koostamisel määrake, millist versiooni me seekord kasutada soovime:

$ mv libhello.a libhello_s.a
$ gcc -o peamine main.o -L. -lhello_s
$ ldd peamine
linux-vdso.so.1 \u003d\u003e (0x00007fff021f5000)
libc.so.6 \u003d\u003e /lib/libc.so.6 (0x00007fd0d0803000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd0d0ba4000)
$ du-h peamine
12K peamine

Kuna libhello teegi koodi suurus on tühine,

$ du -h libhello_s.a
4.0K libhello.a

saadud käivitatava faili suurus praktiliselt ei erine dünaamilise linkimise abil loodud faili suurusest.

Noh, see on vist kõik. Suur tänu kõigile, kes sel hetkel lugemise lõpetasid.

Levinud arvamuse kohaselt on GCC jõudluse poolest teistest koostajatest maha jäänud. Selles artiklis proovime välja mõelda, milliseid põhilisi GCC kompilaatori optimeerimisi tuleks vastuvõetava jõudluse saavutamiseks rakendada.

Millised on GCC vaikesuvandid?

(1) Vaikimisi kasutab GCC optimeerimistaset „-O0”. See pole jõudluse osas ilmselt optimaalne ja seda ei soovitata lõpptoote koostamiseks.
GCC ei tunne ära arhitektuuri, millel kompilatsiooni käitada, kuni suvand "-march \u003d native" on möödunud. GCC kasutab vaikimisi konfigureerimise ajal määratud suvandit. GCC konfiguratsiooni teadasaamiseks lihtsalt käivitage:

See tähendab, et GCC lisab teie valikutele „-march \u003d corei7” (kui pole määratud teistsugust arhitektuuri).
Enamik GCC-i kompilaatorit x86 jaoks (alus 64-bitiseks Linuxi jaoks) lisavad antud suvanditele: “-mtune \u003d generic -march \u003d x86-64”, kuna konfiguratsioonis ei täpsustatud ühtegi arhitektuurivalikut. Käskluse abil saate alati teada kõik GCC käivitamisel läbitud suvandid ja ka selle sisemised suvandid:

Selle tulemusel kasutatakse sageli:

Kasutatav arhitektuur on jõudluse jaoks oluline. Ainsaks erandiks võib pidada neid programme, kus raamatukogu funktsioonide väljakutsumine võtab peaaegu kogu käivitusaja. GLIBC saab käituse ajal valida antud arhitektuuri jaoks optimaalse funktsiooni. Oluline on märkida, et kui staatiliselt seotakse, siis mõnda GLIBC funktsiooni erinevate versioonide jaoks ei versioonita. See tähendab, et dünaamiline kokkupanek on parem, kui GLIBC funktsioonide kiirus on oluline..
(2) Vaikimisi kasutab enamik GCC kompilaatorit 32-bitises 32-bitises režiimis x87 ujukomamudelit, kuna need olid konfigureeritud ilma “-mfpmath \u003d sse”. Ainult siis, kui GCC konfiguratsioon sisaldab “--with-mfpmath \u003d sse”:

kasutab kompilaator vaikimisi SSE-mudelit. Kõigil muudel juhtudel on parem lisada 32-bitises režiimis ehitamisele valik "-mfpmath \u003d sse".
Sageli kasutatakse:

Valiku "-mfpmath \u003d sse" lisamine on 32-bitises režiimis oluline! Erandiks on kompilaator, mille konfiguratsioonis on “--with-mfpmath \u003d sse”.

32 bitti või 64 bitti?

32-bitist režiimi kasutatakse tavaliselt kasutatava mälumahu vähendamiseks ja sellest tulenevalt töö kiirendamiseks (vahemällu paigutatakse rohkem andmeid).
64-bitises režiimis (võrreldes 32-bitise režiimiga) suureneb saadaolevate ühiste registrite arv 6-lt 14-ni, XMM-registrite arv 8-lt 16-ni. Samuti toetavad kõik 64-bitised arhitektuurid SSE2 laiendamist, nii et 64-bitises režiimis ei pea te lisama suvandit -mfpmath. \u003d sse ”.
Ülesannete loendamiseks on soovitatav kasutada 64-bitist režiimi ja mobiilirakenduste jaoks 32-bitist režiimi.

Kuidas saate parima esituse?

Maksimaalse jõudluse jaoks pole konkreetset suvandikomplekti, kuid GCC-l on proovimiseks palju võimalusi. Allpool on tabel, milles on toodud soovitatavad valikud ja kasvuprognoosid Intel Atomi ja 2. põlvkonna Intel Core i7 protsessoritele võrreldes valikuga -O2. Prognoosid põhinevad GCC versiooniga 4.7 koostatud konkreetsete probleemide kogumi tulemuste geomeetrilisel keskmisel. Samuti eeldatakse, et kompilaatori konfiguratsioon tehti x86-64 geneerilise toote jaoks.
Prognooside kohaselt tõuseb jõudlus mobiilirakendused võrreldes -O2-ga (ainult 32-bitises režiimis, kuna see on mobiilsegmendi peamine):

Prognoos jõudluse kasvu kohta arvutusülesannetes võrreldes -O2-ga (64-bitises režiimis):
-m64 -Kiiresti -flto ~17%
-m64-Kiire -flto-marss \u003d emakeel ~21%
-m64 -Kiire -flto-marss \u003d looduslikud -funroll-silmused ~22%

64-bitise režiimi eelis võrreldes 32-bitise arvutusülesande võimalustega „-O2 -mfpmath \u003d sse” on umbes ~ 5%
Kõik artiklis sisalduvad andmed on prognoos, mis põhineb konkreetsete võrdlusaluste komplekti tulemustel.
Allpool on artiklis kasutatud võimaluste kirjeldus. Täielik kirjeldus (inglise keeles): http://gcc.gnu.org/onlinesocs/gcc-4.7.1/gcc/Optimize-Options.html "
  • Sarnane "-Ofast", mis sarnaneb "-O3 -fast-matemaatikaga", võimaldab kõrgemat optimeerimise taset ja agressiivsemat optimeerimist aritmeetiliste arvutuste jaoks (näiteks reaalne taasühinemine)
  • "-flto" moodulitevaheline optimeerimine
  • 32-bitine režiim "-m32"
  • "-mfpmath \u003d sse" võimaldab kasutada XMM-i registreid reaalses aritmeetikas (x87-režiimis reaalse virna asemel)
  • "-funroll-loops" lubab silmuseid lahti kerida

Transpordilogistika (eri transpordiliikide analüüs: eelised, puudused)

Transport on materjalitootmise haru, mis veab inimesi ja kaupu. sotsiaalse tootmise struktuuris tähendab transport materiaalsete teenuste tootmist.

Märgitakse, et oluline osa logistikatoimingutest materjalivoo liikumisel esmasest tooraineallikast lõpptarbimiseni toimub mitmesuguste sõidukite abil. Nende toimingute kulud moodustavad kuni 50% logistika kogukuludest.

Nende eesmärgi järgi eristatakse kahte peamist transpordirühma: Ühistransport on rahvamajanduse haru, mis vastab kõigi rahvamajanduse sektorite ja elanike vajadustele kaupade ja reisijate veol. Ühistransport teenindab ringlust ja elanikke. Seda nimetatakse sageli magistraalliiniks (maantee on mõnes süsteemis peamine, põhiliin, antud juhul sideliinide süsteemis). Ühistranspordi mõiste hõlmab raudteetransport, veetransport (mere- ja jõetransport, maantee-, õhutransport ja torutransport).

Mitte ühistransport - tööstusesisene transport, samuti igat tüüpi sõidukid, mis kuuluvad mittetranspordi organisatsioonide juurde.

Kaupade liikumise korraldamine ühistranspordiga on tootmislogistika teema. Jaotuskanalite valimise ülesanne on lahendatud jaotuslogistika valdkonnas.

Seega on olemas järgmised peamised transpordiliigid:

raudtee

siseveekogu jõgi

auto

õhk

gaasijuhe

Igal transpordiliigil on logistika haldamisel spetsiifilised omadused, eelised ja puudused, mis määravad selle kasutamise võimalused logistikasüsteemis. Transpordikompleksi moodustavad mitmesugused transpordiliigid. Venemaa transpordikompleksi moodustavad tema territooriumil registreeritud juriidilised isikud ja eraisikud - ettevõtjad, kes tegelevad igat tüüpi vedude, raudteede, maanteede ja nende ääres asuvate ehitiste projekteerimise, ehitamise, remondi ja hoolduse, torustike, nendega seotud töödega laevatatavate hüdrokonstruktsioonide, vee ja hingamisteed komisjoni teatised teadusuuringud ja töötajate koolitamine, mis on osa transpordisüsteemist, sõidukeid tootvad ettevõtted, samuti organisatsioonid, kes täidavad muid transpordiprotsessidega seotud töid. Venemaa TK on enam kui 160 tuhat km peamisi raudtee- ja juurdepääsuteid, 750 tuhat km kõvakattega teid, 1,0 miljonit km merelaevaliine, 101 tuhat km siseveeteid, 800 tuhat km lennuettevõtteid. Ainuüksi nende ühenduste kaudu veetakse iga päev ühistranspordiga umbes 4,7 miljonit tonni lasti (2000. aasta seisuga), TC-s töötab üle 4 miljoni inimese ja transpordi osakaal riigi sisemajanduse kogutoodangus on umbes 9%. Seega on transport majanduse infrastruktuuri ning kogu meie riigi kogu sotsiaalse ja tootmispotentsiaali kõige olulisem osa.

Tabel 1 (4, 295) Antakse eri transpordiliikide võrdlevad logistilised omadused.

Tabel 1 Transpordiliikide omadused

Transpordi liik

Eelised

miinused

raudtee

Suur kandevõime. Sõltumatus kliimatingimustest, aastaajast ja päevast.

Transpordi kõrge regulaarsus. Suhteliselt madalad määrad; olulised allahindlused transiitvedude korral. Kaupade kiire kohaletoimetamise kiirus pikkadel vahemaadel.

Vedajate arv piiratud. Suured kapitaliinvesteeringud tootmis- ja tehnilisse baasi. Transpordi kõrge materjali- ja energiakulu. Madal kättesaadavus müügi lõpp-punktidesse (tarbimine).

Lasti ebapiisavalt kõrge ohutus.

Sisudevahelise transpordi võimalus. Madalad pikamaavedude kulud. Suur kandevõime. Transpordi madal kapitalimahukus.

Piiratud vedu.

Madal tarnekiirus (pikk transiidiaeg).

Sõltuvus geograafilistest, navigatsioonilistest ja ilmastikutingimustest.

Vajadus luua keeruline sadamainfrastruktuur.

Sisevesi (jõgi)

Suur kandevõime sügavatel jõgedel ja veekogudel.

Madalad transpordikulud. Madal kapitali intensiivsus.

Piiratud vedu. Madal lasti kohaletoimetamise kiirus.

Sõltuvus jõgede ja veehoidlate ebaühtlasest sügavusest, navigatsioonitingimustest. Hooajalisus. Ebapiisav veo usaldusväärsus ja lasti ohutus.

auto

Kõrge kättesaadavus.

Veose kohaletoimetamise võimalus "uksest ukseni"

Suur juhitavus, paindlikkus, dünaamilisus. Suur kohaletoimetamise kiirus. Erinevate marsruutide ja kohaletoimetamise skeemide kasutamise võimalus.

Suur lastiohutus. Võimalus saata kaupa väikestes partiides.

Kehv esitus. Sõltuvus ilmast ja teeoludest. suhteliselt suured transpordikulud pikkadel vahemaadel.

Ebapiisav ökoloogiline puhtus.

Õhk

Veose suurim kiirus. Suur töökindlus.

Suurim lastiohutus.

Lühimad veoteed.

Transpordi kõrge hind, kõrgeimad tariifid teiste transpordiliikide hulgas. Transpordi kõrge kapitalimahukus, materjali- ja energiakulu. Sõltuvus ilmastikuoludest. Ebapiisav geograafiline ligipääsetavus.

gaasijuhe

Madal omahind. Suur jõudlus (läbilaskevõime). Suur lastiohutus. Madal kapitali intensiivsus.

Piiratud kaubaliigid (gaas, naftatooted, tooraineemulsioonid). Transporditavate kaupade väikeste koguste ebapiisav kättesaadavus.

Nii et kõigepealt peab logistikajuht otsustama, kas luua oma sõidukipark või kasutada renditud sõidukeid (avalikke või eraviisilisi). Alternatiivi valimisel lähtutakse tavaliselt teatud kriteeriumide süsteemist, mis sisaldab järgmist: Oma sõidukipargi loomise ja käitamise kulud. Transporditeenuste, ekspedeerimisettevõtete ja muude logistikavahendajate teenuste eest tasumise maksumus transpordis Transpordi kiirus

Transpordi kvaliteet (tarnekindlus, lastiohutus jne)

Enamasti kasutavad tootmisettevõtted spetsialiseerunud transpordiettevõtete teenuseid.