Erinevate transpordiliikide eelised ja puudused. Transpordilogistika transport. Rahvusvaheline maanteetransport

Linuxi standardse C-kompilaatori gcc õigeks kasutamiseks peate õppima käsurea valikuid. Lisaks laiendab gcc keelt C. Isegi kui kavatsete oma lähtekoodi kirjutada selle keele ANSI standardis, on mõned gcc laiendused, mida peate Linuxi päisefailide mõistmiseks teadma.

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

ISO C standardile vastamine on kasulik, kuid kuna C on madala tasemega keel, on olukordi, kus standardsed funktsioonid ei ole piisavalt väljendusrikkad. Gcc laiendusi kasutatakse laialdaselt kahes valdkonnas: koostekoodiga suhtlemine (neid teemasid käsitletakse aadressil http://www.delorie.com/djgpp/doc/brennan/) ja jagatud teekide loomine (vt 8. peatükk). Kuna päisefailid on jagatud teekide osad, ilmuvad mõned laiendused ka süsteemi päisefailides.

Muidugi on palju rohkem laiendusi, mis on kasulikud mis tahes muus programmeerimises, mis võivad kodeerimisel tõesti abiks olla. Lisateavet nende laiendite kohta leiate gcc Texinfo dokumentatsioonist.

5.1. gcc valikud

gcc aktsepteerib paljusid käsuvalikuid. Õnneks ei ole valikute kogum, millest peaksite tõesti teadlik olema, nii suur ja selles peatükis käsitleme seda.

Enamik valikuid on samad või sarnased teiste kompilaatoritega, gcc sisaldab tohutul hulgal oma valikute dokumentatsiooni, mis on saadaval info gcc kaudu (seda teavet annab ka gcc manleht, kuid käsilehti ei uuendata nii sageli kui Texinfo dokumentatsiooni ).

-o failinimi Määrab väljundfaili nime. Objektfailiks kompileerimisel pole see tavaliselt vajalik, st vaikimisi on failinimi.c asendatud failinimi.o-ga. Kui aga loote käivitatava faili, luuakse see vaikimisi (ajaloolistel põhjustel) nime all a.out . See on kasulik ka siis, kui soovite paigutada väljundfaili teise kataloogi.
- Koos Kompileerib käsureal määratud lähtefaili linkimata. Selle tulemusena luuakse iga lähtefaili jaoks objektifail. Make kasutamisel käivitatakse tavaliselt iga objektifaili jaoks gcc kompilaator; nii on vea korral lihtsam leida, millise faili kompileerimine ebaõnnestus. Kui aga sisestate käske käsitsi, ei ole harvad juhud, kui ühe gcc-kutsega määratakse mitu faili. Kui mitme faili määramisel käsureal 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 .
-Dfoo Määrab käsureal eelprotsessori makrod. Võimalik, et peate loobuma tähemärkidest, mida kest käsitleb erimärkidena. Näiteks stringi defineerides tuleks vältida stringi lõpetavate märkide kasutamist. Kaks levinumat viisi on "-Dfoo="bar"" ja -Dfoo=\"bar\" . Esimene viis töötab palju paremini, kui stringis on tühikuid, sest kest käsitleb tühikuid eriliselt.
-I kataloog Lisab kataloogide loendisse kataloogi, kuhu kaasatud faile otsida.
-L kataloog Lisab kataloogide loendisse kataloogi teekide otsimiseks, gcc eelistab jagatud teeke staatilistele, kui pole teisiti määratud.
- ma foo Lingid lib foo teegi vastu. Kui pole teisiti määratud, eelistab gcc linkimist jagatud teekide vastu (lib foo .so) staatiliste teekide asemel (lib foo .a). Linker otsib funktsioone kõigis loetletud teekides nende loendi järjekorras. Otsing lõpeb, kui kõik vajalikud funktsioonid on leitud.
- staatiline Lingid ainult staatiliste raamatukogudega. Vaata 8. peatükki.
-g , -ggdb Sisaldab silumisinfot. Valik -g paneb gcc kaasama standardse silumise teabe. Valik -ggdb määrab kaasamise tohutu hulk teave, millest saab aru ainult gdb silur.
Kui kettaruumi on vähe või soovite linkimiskiiruse nimel ohverdada mõningaid funktsioone, peaksite kasutama -g . Sel juhul peate võib-olla kasutama muud silurit kui gdb . Kõige täielikumaks silumiseks peate määrama -ggdb . Sel juhul valmistab gcc ette nii palju kui võimalik detailne info gdb jaoks. Tuleb märkida, et erinevalt enamikust kompilaatoritest lisab gcc optimeeritud koodi silumisinfot. Siiski võib optimeeritud koodi siluris jälitamine olla keeruline, kuna käitusaeg võib hüpata ja vahele jätta osa koodist, mida ootate. Siiski on võimalik saada hea esitus selle kohta, kuidas optimeerivad kompilaatorid muudavad koodi täitmise viisi.
-O, -Sees Põhjustab gcc koodi optimeerimise. Vaikimisi teeb gcc vähesel määral optimeerimist; arvu (n) määramisel viiakse optimeerimine läbi teatud tasemel. Kõige tavalisem optimeerimistase on 2; praegu on gcc standardversiooni kõrgeim optimeerimistase 3. Soovitame kasutada -O2 või -O3 ; -O3 võib rakenduse suurust 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 suurust pikema täitmisaja hinnaga. gcc lubab sisseehitatud sisendeid ainult siis, kui on rakendatud vähemalt minimaalne optimeerimine (-O).
-ansi Kõigi ANSI standardite (X3.159-1989) või nende ISO ekvivalendi (ISO/IEC 9899:1990) C-programmide tugi (tavaliselt viidatud kui C89 või harvemini C90). Pange tähele, et see ei taga täielikku vastavust ANSI/ISO standardile.
Valik -ansi keelab gcc laiendused, mis tavaliselt on vastuolus ANSI/ISO standarditega. (Kuna neid laiendusi toetavad paljud teised C-kompilaatorid, ei ole see praktikas probleem.) See määratleb ka makro __STRICT_ANSI__ (nagu on kirjeldatud käesolevas raamatus hiljem), mida päisefailid kasutavad ANSI/ISO-ga ühilduva toetamiseks. keskkond.
-pedantiline Kuvab kõik ANSI/ISO C keelestandardis nõutavad hoiatused ja vead. See ei taga täielikku vastavust ANSI/ISO standardile.
- Sein Võimaldab genereerida kõik gcc hoiatused, mis on tavaliselt kasulik. Kuid see ei hõlma valikuid, mis võivad konkreetsetel juhtudel kasulikud olla. Sarnane detailsuse tase seatakse ka teie lähtekoodi lint-parseri jaoks, gcc võimaldab teil iga kompilaatori hoiatuse käsitsi sisse ja välja lülitada. Gcc käsiraamat kirjeldab üksikasjalikult kõiki hoiatusi.
5.2. päisefailid
5.2.1. pikk pikk

Tüüp long long näitab, et mäluplokk on vähemalt sama suur kui pikk. Intel i86 ja teistel 32-bitistel platvormidel on long 32 bitti, long long aga 64 bitti. 64-bitistel platvormidel kuluvad osutid ja pikad pikkused 64 bitti ning pikad võivad olenevalt platvormist võtta 32 või 64 bitti. Long long tüüpi toetab C99 standard (ISO/IEC 9899:1999) ja see on pikaajaline C laiendus, mida pakub gcc .

5.2.2. Sisseehitatud funktsioonid

Mõned Linuxi päisefailide osad (eriti need, mis on konkreetsele süsteemile omased) kasutavad väga laialdaselt sisseehitatud funktsioone. Need on sama kiired kui makrod (funktsioonikõnede eest tasuta) ja pakuvad igasugust valideerimist, mis on saadaval tavalise funktsioonikõne korral. Sisseehitatud funktsioone kutsuv kood peab kompileerima vähemalt minimaalse optimeerimisega (-O).

5.2.3. Alternatiivsed laiendatud märksõnad

Gcc-s on igal laiendatud märksõnal (märksõnad, mida ANSI/ISO standard ei määratle) kaks versiooni: ise märksõna ja mõlemalt poolt kahe allkriipsuga ümbritsetud märksõna. Kui kompilaatorit kasutatakse standardrežiimis (tavaliselt kui suvand -ansi on lubatud), ei tuvastata tavalisi laiendatud märksõnu. Seega tuleks näiteks päisefaili atribuudi märksõna kirjutada kujul __attribute__ .

5.2.4. Atribuudid

Atribuudi laiendatud märksõna kasutatakse funktsiooni, muutuja või deklareeritud tüübi kohta gcc-le rohkema teabe edastamiseks, kui seda lubab ANSI/ISO C kood. Näiteks joondatud atribuut ütleb gcc-le täpselt, kuidas muutujat või tüüpi joondada; atribuut packed näitab, et polsterdust ei kasutata; noreturn määrab, et funktsioon ei tagasta kunagi, mis võimaldab gcc-l paremini optimeerida ja vältida võltshoiatusi.

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

void die_die_die(int, char*) __atribuut__ ((__noreturn__));

Atribuudideklaratsioon asetatakse sulgude ja semikooloni vahele ning see sisaldab atribuudi märksõna, millele järgneb topeltsulgudes olevad atribuudid. Kui atribuute on palju, tuleks kasutada komadega eraldatud loendit.

printm(char*, ...)

Atribuut__((konst,

formaat(printf, 1, 2)));

Selles näites näete, et printm ei võta arvesse muid väärtusi peale määratud ja sellel pole koodi genereerimisega (const) seotud kõrvalmõjusid, printm näitab, et gcc peaks kontrollima funktsiooni argumente samamoodi nagu printf() argumendid. Esimene argument on vormingu string ja teine ​​argument on esimene asendusparameeter (vorming).

Mõnda atribuuti arutatakse materjali edenedes (näiteks ühisteekide loomise kirjelduse ajal peatükis 8). Põhjalikku teavet atribuutide kohta leiate gcc dokumentatsioonist Texinfo formaadis.

Aeg-ajalt võite leida end Linuxi päisefaile läbi vaatamast. Tõenäoliselt leiate mitmeid kujundusi, mis ei ole ANSI/ISO-ühilduvad. Mõnda neist tasub uurida. Kõiki selles raamatus käsitletud konstruktsioone käsitletakse üksikasjalikumalt gcc dokumentatsioonis.

Aeg-ajalt võite leida end Linuxi päisefaile läbi vaatamast. Tõenäoliselt leiate mitmeid kujundusi, mis ei ole ANSI/ISO-ühilduvad. Mõnda neist tasub uurida. Kõiki selles raamatus käsitletud konstruktsioone käsitletakse üksikasjalikumalt gcc dokumentatsioonis.

Nüüd, kui olete C-standardi kohta veidi õppinud, vaatame võimalusi, mida gcc-kompilaator pakub, et tagada selle vastavus selle keele C-standardile, milles kirjutate. On kolm võimalust tagada, et teie C-kood on standarditega ühilduv ja vigadeta: suvandid, mis määravad, millisele standardi versioonile soovite vastata, definitsioonid, mis juhivad päisefaile, ja hoiatusvalikud, mis käivitavad rangema koodikontrolli.

gcc-l on tohutult palju võimalusi ja siin käsitleme ainult neid, mida peame kõige olulisemaks. Täieliku valikute loendi leiate gcc online man-lehtedelt. Samuti käsitleme lühidalt mõnda #define direktiivi valikut, mida saab kasutada; need tuleks tavaliselt määrata lähtekoodis enne mis tahes #include rida või määratleda gcc käsureal. Teid võib üllatada valikute rohkus, mille abil valida, millist standardit lihtsa lipu asemel kasutada, et sundida kehtivat standardit kasutama. Põhjus on selles, et paljud vanemad programmid tuginevad kompilaatorite ajaloolisele käitumisele ja nende värskendamiseks uusimatele standarditele tuleks teha palju tööd. Harva, kui üldse, soovite oma kompilaatorit värskendada, et see rikuks töötavat koodi. Kuna standardid muutuvad, on oluline, et oleks võimalik töötada vastu teatud standardile, isegi kui see pole standardi uusim versioon.

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

Kui teil on vaja kirjutada ühiskasutuseks mõeldud programm, siis on väga oluline, et teie kood saaks ilma hoiatusteta kompileerida. Kui nõustute mõne hoiatusega ja hakkate neid ignoreerima, võib ühel päeval ilmneda tõsisem hoiatus, millest võite ilma jääda. Kui teie kood kompileerub alati ilma hoiatusteadeteta, jõuab teie tähelepanu kindlasti uus hoiatus. Koodi koostamine ilma hoiatuseta on hea harjumus.

Jälgimisstandardite kompilaatori valikud

Ansi on standardite osas kõige olulisem variant ja paneb kompilaatori tegutsema ISO C90 keelestandardi järgi. See keelab mõned mittestandardsed gcc-laiendid, keelab C++-stiilis kommentaarid (//) C-programmides ja võimaldab käsitleda ANSI-trigraafe (kolmemärgilised jadad). Lisaks sisaldab see makrot __STRICT_ANSI__ , mis keelab päisefailides mõned laiendused, mis standardiga ei ühildu. Kompilaatori tulevastes versioonides võib aktsepteeritud standard muutuda.

Std= – see suvand annab täpsema kontrolli selle üle, millist standardit kasutada, andes parameetri, mis määrab täpselt, millist standardit on vaja. Peamised saadaolevad valikud on järgmised.

C89 - toetab C89 standardit;

Iso9899:1999 – toetab ISO standardi uusimat versiooni C90;

Gnu89 – toetab C89 standardit, kuid lubab mõningaid GNU laiendusi ja mõningaid C99 funktsioone. Gcc versioonis 4.2 on see suvand vaikeseade.

Valikud jälgimisstandardi määratlustes

Seal on konstandid (#defines), mida saab määrata suvanditena käsureal või definitsioonidena programmi lähtekoodis. Üldiselt arvame, et nad kasutavad kompilaatori käsurida.

STRICT_ANSI__ Sunnib kasutama ISO C standardit. Määratletakse, kui kompilaatori käsureal on antud suvand -ansi.

POSIX_C_SOURCE=2 – lubab IEEE Std 1003.1 ja 1003.2 poolt määratletud funktsioonid. Tuleme nende standardite juurde tagasi selles peatükis hiljem.

BSD_SOURCE – võimaldab BSD-süsteemide funktsionaalsust. Kui need on vastuolus POSIX definitsioonidega, on BSD määratlused ülimuslikud.

GNU_SOURCE – võimaldab laia valikut atribuute ja funktsioone, sealhulgas GNU laiendusi. Kui need määratlused on vastuolus POSIX-i definitsioonidega, on viimased ülimuslikud.

Kompilaatori valikud hoiatuste väljastamiseks

Need valikud edastatakse käsurealt kompilaatorile. Ja jällegi loetleme ainult peamised, täielik nimekiri leiate gcc veebipõhisest abikäsiraamatust.

Pedantic on C-koodi kõige võimsam puhastusvalik. Lisaks C-standardile vastavuse kontrollimise võimalusele keelab see mõned traditsioonilised C-konstruktsioonid, mis on standardiga keelatud, ja muudab kõik GNU laiendused standardist ebaseaduslikuks. Seda võimalust tuleks kasutada selleks, et muuta oma C-kood võimalikult kaasaskantavaks.Miinuseks on see, et kompilaator on väga mures sinu koodi puhtuse pärast ja vahel pead sa ajusid rabama, et mõnest allesjäänud hoiatusest lahti saada.

Wformat - kontrollib printf perekonna funktsioonide argumentide tüüpide õigsust.

Wsulud – kontrollib sulgude olemasolu ka seal, kus neid pole vaja. See suvand on väga kasulik kontrollimaks, kas keerukad struktuurid on ettenähtud viisil lähtestatud.

wswitch-default – kontrollib vaikevariandi olemasolu switchi lausetes, mida üldiselt peetakse heaks programmeerimisstiiliks.

Wunused – kontrollib mitmesuguseid juhtumeid, nagu deklareeritud, kuid deklareerimata staatilised funktsioonid, kasutamata parameetrid, kõrvalejäetud tulemused.

Sein – lubab enamiku gcc hoiatustüüpe, sealhulgas kõik eelmised -W suvandid (ainult -pedantic ei ole hõlmatud). Tema abiga on lihtne saavutada programmikoodi puhtus.

Märge

Seal on palju täpsemaid hoiatusvalikuid, vaadake kõiki üksikasju gcc veebilehtedelt. Üldiselt soovitame kasutada -Wall; see on hea kompromiss programmi koodi kontrollimise vahel Kõrge kvaliteet ja kompilaatori vajadus väljastada palju tühiseid hoiatusi, mida on raske tühistada.

GCC on kaasas iga distributsiooniga Linux ja see on tavaliselt vaikimisi seatud. GCC liides on UNIX-i platvormi standardne kompilaatori liides, mis on juurdunud 60ndate lõpus, eelmise sajandi 70ndate alguses - käsurea liides. Ärge kartke, varem on kasutaja interaktsiooni mehhanism sel juhul täiuslikuks lihvitud ja töötage koos GCC-ga (mõne lisautiliit ja hea tekstiredaktor) on lihtsam kui ühegi kaasaegse visuaalse IDE puhul. Komplekti autorid püüdsid rakenduste koostamise ja kokkupanemise protsessi nii palju kui võimalik automatiseerida. Kasutaja kutsub juhtprogrammi gcc, tõlgendab see läbitud käsurea argumente (suvandid ja failinimed) ning iga sisendfaili jaoks, vastavalt kasutatavale programmeerimiskeelele, käivitab oma kompilaatori, seejärel vajadusel gcc kutsub automaatselt välja assembleri ja linkeri (linkeri).

Kummalisel kombel on kompilaatorid üks väheseid UNIX-i rakendusi, mis hoolivad faililaienditest. Laienduse järgi määrab GCC, milline fail selle ees on ja mida sellega teha on vaja (saab). Keeleallika failid C keeles peab olema laiend .c C++, teise võimalusena .cpp , päisefailid selles keeles C.h , .o objektifailid ja nii edasi. Kui kasutate vale laiendit, gcc ei tööta korralikult (kui olete üldse nõus midagi tegema).

Liigume edasi praktika juurde. Kirjutame, kompileerime ja käivitame mõne lihtsa programmi. Ärgem olgem originaalsed, kui keele näidisprogrammi lähtefail C Loome järgmise sisuga faili:

/* hello.c */

#kaasa

Main( tühine )
{

Printf("Tere maailm\n" );

tagasi 0 ;

Nüüd anname kataloogis c hello.c välja käsu:

$ gcc hello.c

Mõne sekundi murdosa pärast ilmub kataloogi fail a.out:

$ls
a.out tere.c

See on meie programmi valmis täitmisfail. Vaikimisi gcc annab väljundkäivitavale failile nime a.out (kunagi tähendas see nimi monteerija väljund).

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

Käivitame saadud tulemuse tarkvara:

$ ./a.out
Tere, Maailm


Miks on praegusest kataloogist faili käivitamiseks vaja käsus Run selgesõnaliselt määrata faili tee? Kui käivitatava faili tee pole selgesõnaliselt määratud, otsib kest käske tõlgendades faili kataloogidest, mille loendit määrab süsteemimuutuja PATH.

$ kaja $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Kataloogid loendis on eraldatud koolonitega. Failide otsimisel vaatab kest katalooge läbi nende loetletud järjekorras. Vaikimisi on turvakaalutlustel praegune kataloog . ei ole loendis; seetõttu ei otsi kest sellest käivitatavaid faile.

Miks ei soovitata teha . aastal PATH? Arvatakse, et tõelises mitme kasutajaga süsteemis leidub alati mõni halb inimene, kes paneb avalikku kataloogi pahatahtliku programmi käivitatava failinimega, mis ühtib mõne käsu nimega, mida kohalik administraator sageli superkasutajaga kutsub. õigused ... Süžee õnnestub , kui . on kataloogi loendi alguses.


Kasulikkus faili kuvab infot käsureal edastatud faili tüübi kohta (süsteemi vaatenurgast), teatud tüüpi faili puhul kõikvõimalikke Lisainformatsioon faili sisu kohta.

$fail hello.c
hello.c: ASCII C programmi tekst
$faili annotatsioon.doc
annotation.doc: CDF V2 dokument, Little Endian, OS: Windows, versioon 5.1, koodileht: 1251, autor: MIH, mall: Normal.dot, viimati salvestanud: MIH, versiooni number: 83, rakenduse loomise nimi: Microsoft Office Word, redigeerimise koguaeg: 09:37:00, viimati trükitud: neljapäev jaanuar 22 07:31:00 2009, loomise aeg/kuupäev: esmaspäev jaanuar 12 07:36:00 2009, viimati salvestatud aeg/kuupäev: neljapäev, 22. jaanuar 07:34:00 2009, Lehekülgede arv: 1, Sõnade arv: 3094, Tähemärkide arv: 17637, Turvalisus: 0

See on tegelikult kõik, mida kasutajalt edukaks rakendamiseks nõutakse gcc :)

Väljundkäivitatava faili nimi (nagu ka mis tahes muu faili, mille on loonud gcc) saab muuta koos valikud -o:

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


Meie näites tagastab funktsioon main() näiliselt mittevajaliku väärtuse 0 . UNIX-i laadsetes süsteemides on programmi lõpus kombeks kesta täisarv tagastada - eduka täitmise korral null, muul juhul. Shelli interpretaator määrab saadud väärtuse automaatselt keskkonnamuutujale nimega ? . Saate vaadata selle sisu kasutades echo $? :

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

Sellest öeldi eespool gcc on juhtimisprogramm, mis on loodud kompileerimisprotsessi automatiseerimiseks. Vaatame, mis tegelikult juhtub käsu gcc hello.c täitmise tulemusena.

Kompileerimisprotsessi saab jagada 4 põhietappi: eelprotsessori töötlemine, tegelik kompileerimine, kokkupanek, linkimine (sidumine).

Valikud gcc võimaldab teil protsessi mis tahes etapis katkestada.

Eeltöötleja valmistab lähtefaili kompileerimiseks ette - lõikab välja kommentaarid, lisab päisefailide sisu (eeltöötleja käskkiri #include ), rakendab makrode laiendamist (sümboolsed konstandid, eelprotsessori käsk #define ).

Kasu lõikama -E variant edasisi tegevusi gcc saate katkestada ja vaadata eeltöötleja poolt töödeldud faili sisu.

$ gcc -E -o tere.i tere.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 unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
. . .
extern int printf (__const char *__restrict __format, ...);
. . .
#4 "tere.c" 2
peamine (tühine)
{
printf("Tere maailm\n");
tagasi 0;
}

Pärast eeltöötleja poolt töötlemist meie programmi lähtetekst paisus ja omandas loetamatu kuju. Kood, mille me kunagi oma kätega sisestasime, vähendati faili lõpus mõneks reale. Põhjuseks on standardteegi päisefaili kaasamine C. Päisefail stdio.h ise sisaldab palju erinevaid asju ja nõuab ka teiste päisefailide kaasamist.

Pange tähele faililaiendit hello.i. Kokkulepete järgi gcc laiend .i vastab failidele, mille lähtekood on selles keeles C ei vaja eelprotsessori töötlemist. Sellised failid kompileeritakse eelprotsessorist mööda minnes:

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

Pärast eeltöötlust tuleb koostamise kord. Kompilaator teisendab kõrgetasemelises keeles programmi lähtekoodi assemblykeelseks koodiks.

Sõna koostamine tähendus on ebamäärane. Vikipedistid näiteks kaaluvad, viidates rahvusvahelistele standarditele see kompileerimine on "teisendus kompilaatoriprogrammi poolt lähtekood mis tahes programm, mis on kirjutatud kõrgetasemelises programmeerimiskeeles, masinkoodile lähedasesse keelde või objektkoodi." Põhimõtteliselt see definitsioon meile sobib, assemblerkeel on tõesti masinakeelele lähemal kui C. Kuid igapäevaelus mõistetakse kompileerimise all enamasti lihtsalt mis tahes toimingut, mis teisendab mis tahes programmeerimiskeeles programmi lähtekoodi käivitatavaks koodiks. See tähendab, et protsessi, mis hõlmab kõiki nelja ülaltoodud etappi, võib nimetada ka kompileerimiseks. Sarnane mitmetähenduslikkus esineb ka käesolevas tekstis. Teisest küljest võib programmi lähteteksti teisendamist komplekteerimiskeele koodiks tähistada ka sõnaga tõlkimine - "ühes programmeerimiskeeles esitatud programmi teisendamine teise keele programmiks ja teatud mõttes samaväärne esimesega."

Peatage käivitatava faili loomise protsess kompileerimise lõpus -S variant:

$ gcc -S tere.c
$ls
tere.c tere.s
$fail tere.s
hello.s: ASCII assemblerprogrammi tekst
$ vähem tere.s
.fail "tere.c"
.section .rodata
.LC0:
.string "Tere maailm"
.tekst
.glob main
.type main, @function
peamine:
pushl %ebp
movl %esp, %ebp
jal $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
kõne paneb
movl $0, %eax
lahkuda
ret
.suurus põhi, .-pea


Kataloogi ilmus fail hello.s, mis sisaldab programmi installatsioonikeeles. Pange tähele, et väljundfaili nime määramine valikud -o antud juhul polnud see vajalik gcc genereeris selle automaatselt, asendades lähtefaili nimes laiendi .c laiendiga .s. Enamiku põhitoimingute jaoks gcc väljundfaili nimi moodustatakse sellise asendusega. Laiendus .s on assemblerkeele lähtefailide standardne.

Loomulikult saate käivitatava koodi ka failist hello.s:

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

Koosteoperatsiooni järgmine etapp on montaažikeele koodi tõlkimine masinkoodiks. Operatsiooni tulemuseks on objektifail. Objektifail sisaldab täitmiseks valmis masinakoodi plokke, andmeplokke ning failis määratletud funktsioonide ja väliste muutujate loendit ( sümbolite tabel ), kuid samas ei täpsusta see funktsioonide ja andmete viidete absoluutaadresse. Objekti faili ei saa käivitada otse, kuid hiljem (linkimise etapis) saab seda kombineerida teiste objektifailidega (sel juhul arvutatakse ja täidetakse vastavalt sümbolitabelitele failide vahel olemasolevate ristviidete aadressid ). Võimalus gcc-c , peatab protsessi montaažietapi lõpus:

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

Objektifailid kasutavad standardset laiendit .o.

Kui vastuvõetud objektifail hello.o edastatakse linkerile, arvutab viimane linkide aadressid, lisab programmi käivitamise ja lõpetamise koodi, teegi funktsioonide väljakutsumise koodi ning selle tulemusena saame valmis - tehtud programmi käivitatav fail.

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

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

Noh, võib-olla kogumise ja muu kohta. Nüüd puudutame mõningaid minu arvates olulisi võimalusi. gcc.

Variant - I tee/kataloogi/koos/päisega/failidega - lisab määratud kataloogi päisefailide otsinguteede loendisse. Kataloog lisatud valikuga - Mina esmalt otsitakse, seejärel jätkub otsing standardsetes süsteemikataloogides. Kui valikud - Mina mitu, skannitakse nende määratud katalooge valikute ilmumisel vasakult paremale.

- Seina võimalus- kuvab hoiatusi, mis on põhjustatud võimalikest koodis esinevatest vigadest, mis ei takista programmi kompileerimist, kuid mis võivad kompilaatori hinnangul kaasa tuua teatud probleeme selle täitmisel. Oluline ja kasulik valik, arendajad gcc soovitame seda alati kasutada. Näiteks kuvatakse sellise faili kompileerimisel palju hoiatusi:

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


$ gcc -o märkus märkus.c
$ gcc -Seina -o märkus märkus.c
remark.c:7: hoiatus: tagastamise tüüp on vaikimisi "int"

märkus.c:13: hoiatus: avaldus, millel puudub mõju
märkus.c:9: hoiatus: kasutamata muutuja 'a'
märkus.c:21: hoiatus: juhtimine jõuab mittetühise funktsiooni lõpuni
remark.c: tipptasemel:
märkus.c:3: hoiatus: 'k' on määratletud, kuid ei kasutata
märkus.c:4: hoiatus: "l" kuulutati "staatiliseks", kuid pole kunagi määratletud
remark.c: funktsioonis 'main':
märkus.c:15: hoiatus: selles funktsioonis kasutatakse 'c' lähtestamata
märkus.c:19: hoiatus: selles funktsioonis kasutatakse 'p' lähtestamata

Valik - viga- muudab kõik hoiatused vigadeks. Hoiatuse korral katkestab kompileerimisprotsessi. Kasutatakse koos - Seina võimalus.

$ gcc -Werror -o märkus märkus.c
$ gcc -Werror -Wall -o märkus märkus.c
cc1: hoiatusi käsitletakse vigadena
remark.c:7: viga: tagastustüübi vaikeväärtus on "int"
remark.c: funktsioonis 'main':
märkus.c:13: viga: avaldus, millel puudub mõju
remark.c:9: viga: kasutamata muutuja 'a'

Valik -g- paigutab siluri töötamiseks vajaliku teabe objekti või käivitatavasse faili gdb. Kui ehitate projekti hilisema silumise eesmärgil, valik -g tuleb lisada nii koostamise kui ka linkimise ajal.

Valikud -O1 , -O2 , -O3- määrake kompilaatori poolt genereeritud koodi optimeerimise tase. Kui arv suureneb, suureneb optimeerimise aste. Valikute tegevust saab näha selles näites.

Algne fail:

/* circle.c */

Main( tühine )
{

int i;

jaoks(i = 0; i< 10 ; ++i)
;

tagasi i;

Kompileerimine optimeerimise vaiketasemega:

$ gcc -S ring.c
$ vähem suhtlusringe
.fail "circle.c"
.tekst
.glob main
.type main, @function
peamine:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L3:
addl $1, -4(%ebp)
.L2:
cmpl $9, -4(%ebp)
jle .L3
movl -4(%ebp), %eax
lahkuda
ret
.suurus põhi, .-pea
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits

Maksimaalse optimeerimistasemega kompileerimine:

$ gcc -S -O3 ring.c
$ vähem suhtlusringe
.fail "circle.c"
.tekst
.p2align 4.15
.glob main
.type main, @function
peamine:
pushl %ebp
movl $10, %eax
movl %esp, %ebp
popl %ebp
ret
.suurus põhi, .-pea
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits

Teisel juhul pole saadud koodis isegi vihjet ühelegi tsüklile. Tõepoolest, i väärtust saab arvutada kompileerimisetapis, mis ka tehti.

Paraku on tegelike projektide puhul jõudluse erinevus erinevatel optimeerimistasemetel peaaegu märkamatu...

Valik -O0- tühistab igasuguse koodi optimeerimise. Valik on vajalik rakenduse silumise etapis. Nagu ülal näidatud, võib optimeerimine viia programmi struktuuri tundmatuseni muutumiseni, ühendus käivitatava faili ja lähtekoodi vahel ei ole selgesõnaline, vastavalt ei ole programmi samm-sammult silumine võimalik. Kui valik on lubatud -g, on soovitatav lisada ja -O0.

-Os variant- määrab optimeerimise mitte koodi efektiivsuse, vaid tulemuseks oleva faili suuruse järgi. Programmi jõudlus peaks olema võrreldav vaikimisi optimeerimistasemega kompileerimisel saadud koodi jõudlusega.

Valik -march=arhitektuur- määrab protsessori sihtarhitektuuri. Toetatud arhitektuuride loend on ulatuslik, näiteks pereprotsessorite jaoks Intel/AMD saate määrata i386, pentium, prescott, opteron-sse3 jne. Binaarsete distributsioonide kasutajad peaksid meeles pidama, et määratud valikuga programmide korrektseks toimimiseks on soovitav, et kõik kaasatud teegid oleksid kompileeritud sama valikuga.

Linkerile edastatud valikuid käsitletakse allpool.

Väike täiendus:

Sellest öeldi eespool gcc määrab edastatavate failide tüübi (programmeerimiskeele) nende laienduse järgi ja teeb nendega toiminguid vastavalt arvatavale tüübile (keelele). Kasutaja on kohustatud jälgima loodud failide laiendusi, valides need vastavalt lepingutele gcc. Tegelikult gcc saate panna suvaliste nimedega faile. gcc -x valik võimaldab selgesõnaliselt määrata kompileeritud failide programmeerimiskeele. Suvandi toiming rakendub kõigile järgmistele käsus loetletud failidele (kuni järgmise valiku ilmumiseni -x). Võimalikud valikuargumendid:

c c-päis c-cpp-väljund

c++ c++-päis c++-cpp-väljund

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

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

monteerija assembler-koos-cpp

ada

f77 f77-cpp-sisend

f95 f95-cpp-sisend

java

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

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

Eraldi koostamine

Keelte tugev külg C/C++ on võimalus jagada programmi lähtekood mitmeks failiks. Võib isegi rohkem öelda - eraldi koostamise võimalus on keele alus, ilma selleta tõhus kasutamine C pole mõeldav. See on mitme faili programmeerimine, mis võimaldab teil seda edasi rakendada C suured projektid nagu Linux(siin sõna all Linux nii tuum kui ka süsteem tervikuna). Mis annab programmeerijale eraldi kompileerimise?

1. Võimaldab muuta programmi (projekti) koodi loetavamaks. Mitmekümne ekraani lähtefail muutub peaaegu ülekaalukaks. Kui jagate selle teatud (ettevalmistatud) loogika kohaselt mitmeks väikeseks killuks (igaüks eraldi failis), on projekti keerukusega palju lihtsam toime tulla.

2. Vähendab projekti ümberkompileerimise aega. Kui ühes failis tehakse muudatusi, ei ole mõtet kogu projekti uuesti kompileerida, piisab ainult selle muudetud faili uuesti kompileerimisest.

3. Võimaldab jagada projektitööd mitme arendaja vahel. Iga programmeerija loob ja silub oma osa projektist, kuid igal ajal on võimalik koguda (ümber ehitada) kõik sellest tulenevad arendused lõpptooteks.

4. Ilma eraldi koostamiseta poleks raamatukogusid. Teekide kaudu, koodi taaskasutamine ja levitamine C/C++, ja kood on binaarne, mis võimaldab ühelt poolt pakkuda arendajatele lihtsat mehhanismi selle lisamiseks oma programmidesse, teisalt varjata nende eest konkreetseid juurutamise üksikasju. Kas projekti kallal töötades tasub alati mõelda ja mitte kunagi tulevikus mitte midagi vajada juba tehtust? Võib-olla tasub osa koodist eelnevalt esile tõsta ja raamatukoguks korraldada? Minu arvates lihtsustab selline lähenemine oluliselt elu ja säästab palju aega.

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

Siin on praktiline näide (kuigi väga, väga tingimuslik).

Lähtekoodifailide komplekt:

/* main.c */

#kaasa

#include "first.h"
#include "second.h"

int main( tühine )
{

esimene();
teine();

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

tagasi 0 ;


/* esimene.h */

tühine esimene ( tühine );


/* first.c */

#kaasa

#include "first.h"

tühine esimene ( tühine )
{

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


/* sekund.h */

tühine teine ​​( tühine );


/* second.c */

#kaasa

#include "second.h"

tühine teine ​​( tühine )
{

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

Üldiselt on meil see:

$ls
esimene.c esimene.h põhi.c teine.c teine.h

Kogu selle majanduse saab koondada ühte käsku:

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

Ainult see ei anna meile praktiliselt mingeid boonuseid, välja arvatud struktureeritum ja loetavam kood, mis on jagatud mitme faili vahel. Selle koostamisviisi puhul ilmnevad kõik ülaltoodud eelised:

$ gcc -Wall -c main.c
$ gcc -Wall -c first.c
$ gcc -Sein -c second.c
$ls
esimene.c esimene.h esimene.o põhi.c põhi.o teine.c teine.h teine.o
$ gcc -o peamine main.o esimene.o teine.o
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

Mida me oleme teinud? Igast lähtefailist (koostamisel valikuga -c) sai objektifaili. Seejärel lingiti objektifailid lõplikku käivitatavasse faili. Muidugi käsud gcc neid on rohkem, kuid keegi ei pane projekte käsitsi kokku, selleks on komplekteerimisutiliidid (kõige populaarsem tegema). Assembleri utiliitide kasutamisel ilmnevad kõik ülaltoodud eraldiseisva kompileerimise eelised.

Tekib küsimus: kuidas õnnestub linkeril objektifaile kokku panna, arvutades õigesti kõneaadressi? Kuidas ta üldse teab, et fail second.o sisaldab funktsiooni second() koodi ja main.o failikood sisaldab selle kutset? Selgub, et kõik on lihtne – objektifailis on nn sümbolite tabel , mis sisaldab mõnede koodipositsioonide nimesid (funktsioonid ja välised muutujad). Linker vaatab läbi iga objektifaili sümbolitabeli, otsib ühiseid (vastavate nimedega) positsioone, mille põhjal teeb järeldusi kasutatavate funktsioonide (või andmeplokkide) koodi tegeliku asukoha kohta ning vastavalt arvutab uuesti käivitatavas failis olevad kõneaadressid.

Sümbolitabelit saate vaadata utiliidi abil nm.

$nm main.o
S esimene
00000000 T põhi
U paneb
U teiseks
$nm first.o
00000000 T kõigepealt
U paneb
$nm second.o
U paneb
00000000 T sekundis

Puts-kutse on tingitud standardse teegifunktsiooni printf() kasutamisest, millest kompileerimise ajal sai puts().

Sümbolitabel kirjutatakse mitte ainult objektifaili, vaid ka käivitatavasse faili:

$ nm peamine
08049f20d_DYNAMIC
08049ff4d _GLOBAL_OFFSET_TABLE_
080484fc R _IO_stdin_used
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0cd __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048538r __FRAME_END__
08049f1cd __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
08049f0cd __init_array_end
08049f0cd __init_array_start
08048440 T __libc_csu_fini
08048450 T __libc_csu_init
U __libc_start_main@@GLIBC_2.0
0804a014 A _edata
0804a01c A_end
080484dc T_fini
080484f8 R_fp_hw
080482b8 T _init
08048330 T_start
0804a014b lõpetatud.7021
0804a00c W data_start
0804a018 b dtor_idx.7023
0804840c T esimene
080483c0 t frame_dummy
080483e4 T põhi
U puts@@GLIBC_2.0
08048420 T sekund

Sümbolitabeli lisamine käivitatavasse faili on eriti vajalik silumise hõlbustamiseks. Põhimõtteliselt pole seda rakenduse käivitamiseks tegelikult vaja. Päris programmi käivitatavate failide puhul, millel on palju funktsioonide määratlusi ja väliseid muutujaid, mis hõlmavad hunnikut erinevaid teeke, muutub sümbolite tabel üsna ulatuslikuks. Väljundfaili suuruse vähendamiseks saab selle eemaldada kasutades gcc -s valik.

$ gcc -s -o peamine main.o esimene.o teine.o
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...
$ nm peamine
nm: peamine: sümboleid pole

Tuleb märkida, et linkimise ajal ei kontrolli linker funktsioonikutse konteksti, ei jälgi tagastatava väärtuse tüüpi ega vastuvõetud parameetrite tüüpi ja arvu (ja tal pole selliseid kusagilt hankida). teave alates). Kogu kõne valideerimine tuleb teha kompileerimise ajal. Mitme failiga programmeerimise puhul on vaja selleks kasutada keele päisefailide mehhanismi. C.

raamatukogud

Raamatukogu – keeles C, fail, mis sisaldab objektikoodi, mille saab linkimisfaasis teeki kasutades programmile lisada. Tegelikult on raamatukogu spetsiaalselt lingitud objektifailide kogum.

Teekide eesmärk on pakkuda programmeerijale koodi taaskasutamiseks standardset mehhanismi ning mehhanism on lihtne ja töökindel.

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

Staatiline teegi kood lisatakse käivitatavasse faili viimase linkimisel. Teek "ühendatakse" failiga, raamatukogu kood "liidetakse" ülejäänud faili koodiga. Staatilisi teeke kasutav programm muutub iseseisvaks ja seda saab käivitada praktiliselt igas õige arhitektuuri ja operatsioonisüsteemiga arvutis.

Jagatud teegi koodi laadib ja seob programmi koodiga operatsioonisüsteem programmi palvel selle täitmise ajal. Dünaamilise teegi kood ei sisaldu programmi käivitatavas failis, täitmisfailis on ainult link teegile. Selle tulemusena ei ole jagatud teeke kasutav programm enam iseseisev ja seda saab edukalt käivitada ainult süsteemis, kuhu on installitud asjaomased teegid.

Jagatud raamatukogu paradigmal on kolm olulist eelist:

1. Käivitatava faili suurus on oluliselt vähenenud. Süsteemis, mis sisaldab palju sama koodi kasutavaid binaarfaile, ei ole vaja iga käivitatava faili jaoks selle koodi koopiat säilitada.

2. Mitme rakenduse kasutatav jagatud teegi kood salvestatakse RAM-i ühel eksemplaril (tegelikult pole see nii lihtne...), mille tulemusena väheneb süsteemi vajadus saadaoleva RAM-i järele.

3. Kui jagatud teegi koodi muudetakse, pole vaja iga käivitatavat faili uuesti üles ehitada. Dünaamilise teegi koodi muudatused ja parandused kajastuvad automaatselt igas seda kasutavas programmis.

Ilma jagatud raamatukogu paradigmata poleks eelkompileeritud (binaarseid) distributsioone Linux(jah, ükskõik mida). Kujutage ette jaotuse suurust, mille igasse kahendfaili oleks paigutatud standardne teegikood. C(ja kõik muud kaasatud raamatukogud). Kujutage vaid ette, mida peaksite tegema süsteemi värskendamiseks pärast kriitilise haavatavuse parandamist ühes laialdaselt kasutatavas teegis...

Nüüd natuke harjutamiseks.

Illustreerimiseks kasutame eelmise näite lähtefailide komplekti. Asetame omatehtud teeki funktsioonide first() ja second() koodi (rakenduse).

Linuxil on teegifailide jaoks järgmine nimetamisskeem (kuigi seda ei järgita alati) - teegifaili nimi algab eesliitega lib , millele järgneb teegi tegelik nimi ja lõpus laiendiga .a ( arhiiv ) - staatilise raamatukogu jaoks, .so ( jagatud objekt ) - jagatud (dünaamilise) puhul on pärast laiendamist versiooninumbri numbrid loetletud punktiga (ainult dünaamilise teegi puhul). Teegile vastava päisefaili nimi (reeglina jällegi) koosneb teegi nimest (ilma eesliiteta ja versioonita) ja laiendist .h . Näiteks: libogg.a , libogg.so.0.7.0 , ogg.h .

Esiteks loome ja kasutame staatilise teeki.

Funktsioonid first () ja second () moodustavad meie libhello teegi sisu. Teegi faili nimi on vastavalt libhello.a . Võrdleme päisefaili hello.h teegiga.

/* tere.h */

tühine esimene ( tühine );
tühine teine ​​( tühine );

Muidugi read:

#include "first.h"


#include "second.h"

failides main.c , first.c ja second.c tuleb asendada järgmisega:

#include "tere.h"

Noh, nüüd sisestage järgmine käskude jada:

$ gcc -Wall -c first.c
$ gcc -Sein -c second.c
$ ar crs libhello.a first.o second.o
$filelibhello.a
libhello.a: praegune arhiiv

Nagu juba mainitud, on raamatukogu objektifailide kogum. Kahe esimese käsuga lõime need objektifailid.

Järgmiseks peate linkima objektifailid komplekti. Selleks kasutatakse arhiveerijat. ar- utiliit "liimib" mitu faili ühte, saadud arhiiv sisaldab iga üksiku faili taastamiseks (väljavõtmiseks) vajalikku teavet (sh selle omandi, juurdepääsu, aja atribuudid). Arhiivi sisu "tihendamist" ega salvestatud andmete muud transformatsiooni ei teostata.

c arname valik- loo arhiiv, kui arhiivi nimega arname ei eksisteeri, siis see luuakse, vastasel juhul lisatakse failid olemasolevasse arhiivi.

r valik- määrab arhiivi uuendamise režiimi, kui määratud nimega fail on arhiivis juba olemas, siis see kustutatakse ja uus fail lisatakse arhiivi lõppu.

Valik s- lisab (värskendab) arhiiviindeksit. Sel juhul on arhiivindeks tabel, milles iga arhiveeritud failides määratletud sümboolse nime (funktsiooni või andmeploki nime) jaoks on sellega seotud vastav objektifaili nimi. Arhiiviregister on vajalik raamatukoguga töö kiirendamiseks – soovitud definitsiooni leidmiseks pole vaja kõigi arhiivifailide sümbolitabeleid läbi vaadata, saab kohe minna otsitava nime sisaldava faili juurde . Arhiiviregistrit saate vaadata juba tuttava utiliidi abil nm kasutades seda valik -s(kuvatakse ka kõigi arhiivi objektifailide sümbolitabelid):

$ nm -s libhello.a
arhiivi register:
esimene esimeses.o
teine ​​teises.o

first.o:
00000000 T kõigepealt
U paneb

second.o:
U paneb
00000000 T sekundis

Arhiiviindeksi loomiseks on spetsiaalne utiliit ranlib. Teeki libhello.a oleks võinud luua järgmiselt:

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

Kuid raamatukogu töötab hästi ka ilma arhiiviregistrita.

Nüüd kasutame oma raamatukogu:

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

Töötab...

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

-l nime valik- edastatakse linkerile, näitab vajadust linkida libname teek käivitatava failiga. Ühendus tähendab, et sellised ja sellised funktsioonid (välised muutujad) on määratletud sellises ja sellises teegis. Meie näites on teek staatiline, kõik sümboolsed nimed viitavad koodile, mis asub otse käivitatavas failis. Pöörake tähelepanu valikutele -l teegi nimi antakse nimena ilma lib-eesliiteta.

Valik -L /tee/kataloogi/koos/teegid - edastatakse linkerile, määrab lingitud teeke sisaldava kataloogi tee. Meie puhul punkt . , otsib linker esmalt teeke praegusest kataloogist ja seejärel süsteemis määratletud kataloogidest.

Siin on vaja teha väike märkus. Fakt on see, et mitme valiku puhul gcc oluline on nende käsureale ilmumise järjekord. Nii otsib linker käsureal loetletud teekides koodi, mis ühtib faili sümbolitabelis määratud nimedega pärast selle faili nimi. Linker ignoreerib failinime ees loetletud teekide sisu:

$ gcc -Wall -c main.c
$ gcc -o main -L. -tere main.o
main.o: funktsioonis "main":
main.c:(.text+0xa): määratlemata viide "esimesele"
main.c:(.text+0xf): määramata viide 'sekundile'

$ gcc -o peamine main.o -L. - tere
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

Selline käitumine gcc tänu arendajate soovile pakkuda kasutajale võimalust faile erinevatel viisidel raamatukogudega kombineerida, kasutada ristuvaid nimesid ... Minu arvates on võimalusel parem sellega mitte vaeva näha. Üldiselt peaksid lingiteekid olema loetletud neile viitava faili nime järel.

Olemas alternatiivne viis teekide asukoha määramine süsteemis. Olenevalt distributsioonist võib keskkonnamuutuja LD_LIBRARY_PATH või LIBRARY_PATH sisaldada kooloniga eraldatud loendit kataloogidest, millest linker peaks teeke otsima. Reeglina ei ole see muutuja vaikimisi üldse määratletud, kuid miski ei takista selle loomist:

$ kaja $LD_LIBRARY_PATH

/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../i686-pc-linux-gnu/bin/ld: ei leia -lhello
collection2: ld väljus tagastamiskoodiga 1
$ eksport LIBRARY_PATH=.
$ gcc -o main main.o -lhello
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

Keskkonnamuutujatega manipuleerimine on kasulik oma teekide loomisel ja silumisel, samuti juhul, kui tekib vajadus ühendada rakendusega mõni mittestandardne (vananenud, värskendatud, muudetud - üldiselt erinev levitamiskomplektis sisalduvast) jagatud teegist.

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

Lähtefailide komplekt jääb muutumatuks. Sisestame käsud, vaatame, mis juhtus, loe kommentaare:

$ gcc -Sein -fPIC -c esimene.c
$ gcc -Sein -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 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. Räägime selle kasutamisest allpool.

Nüüd kommentaarid:

Valik -fPIC- nõuab objektifailide loomisel kompilaatorilt genereerimist positsioonist sõltumatu kood (PIC – positsioonist sõltumatu kood ), selle peamine erinevus seisneb aadresside esitamise viisis. Fikseeritud (staatiliste) positsioonide määramise asemel arvutatakse kõik aadressid punktis määratud nihete alusel globaalne nihketabel (globaalne nihketabel – 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 võimalus- näitab gcc, et selle tulemusena ei tuleks ehitada käivitatav fail, vaid jagatud objekt - dünaamiline teek.

Valik -Wl,-soname,libhello.so.2- komplektid soname raamatukogud. Sonamest räägime üksikasjalikult järgmises lõigus. Nüüd arutame valiku vormingut. See esmapilgul kummaline komadega konstruktsioon on mõeldud otseseks suhtluseks kasutaja ja linkeri vahel. Koostamise ajal gcc kutsub linkerit automaatselt, automaatselt, omal äranägemisel, gcc annab talle edasi töö edukaks sooritamiseks vajalikud valikud. Kui kasutajal on vaja linkimisprotsessi ise sekkuda, saab ta kasutada spetsiaalset võimalust gcc -Wl, -valik , väärtus1 , väärtus2 .... Mida tähendab linkerile edastamine ( -Wl) valik - valik argumentidega väärtus1, väärtus2 ja nii edasi. Meie puhul anti linkerile võimalus -soname argumendiga libhello.so.2.

Nüüd soname kohta. Teekide loomisel ja levitamisel on probleem ühilduvuse ja versioonikontrolliga. Selleks, et süsteemil, täpsemalt dünaamilisel teegilaaduril, oleks ettekujutus sellest, millist teegi versiooni rakenduse koostamisel kasutati ja mis on vastavalt selle edukaks tööks vajalik, pakuti spetsiaalne identifikaator - soname , mis on paigutatud nii teegifaili endasse kui ka rakenduse käivitatavasse faili. Soname identifikaator on string, mis sisaldab teegi nime eesliitega lib , punkti, laiendit so, uuesti punkti ja ühte või kahte (punktidega eraldatud) numbrit teegi versioonist lib name .so. x . y . See tähendab, et soname vastab raamatukogu faili nimele kuni versiooninumbri esimese või teise numbrini. Olgu meie teegi käivitatava faili nimi libhello.so.2.4.0.5 , siis võiks teegi soname olla libhello.so.2 . Teegi liidese muutmisel tuleb muuta selle soname! Kõikidele koodimuudatustele, mis põhjustavad kokkusobimatust eelmiste väljalasetega, peab olema kaasas uus soname.

Kuidas see kõik toimib? Olgu mõne rakenduse edukaks täitmiseks nõutav teek nimega hello, olgu see süsteemis olemas ja teegi faili nimi on libhello.so.2.4.0.5 ja sellesse kirjutatud teegi soname on libhello .nii.2 . Rakenduse koostamise etapis linker, vastavalt valikule -Tere, otsib süsteemist faili nimega libhello.so. Reaalses süsteemis on libhello.so sümboolne link failile libhello.so.2.4.0.5 . Pärast teegifaili avamist loeb linker selles registreeritud soname väärtuse ja muuhulgas paigutab selle rakenduse käivitatavasse faili. Rakenduse käivitamisel saab dünaamilise teegi laadija taotluse lisada teek, mille soname on loetud käivitatavast failist, ja proovib leida süsteemist teeki, mille failinimi kattub nimega soname. See tähendab, et laadija püüab leida faili libhello.so.2. Kui süsteem on õigesti konfigureeritud, peaks see sisaldama sümboolset linki libhello.so.2 faili libhello.so.2.4.0.5 , laadija saab juurdepääsu vajalikule teegile ja seejärel kõhklemata (ja midagi muud kontrollimata) ühendage see rakendusega. Kujutage nüüd ette, et oleme teisaldanud sel viisil koostatud rakenduse teise süsteemi, kus on juurutatud ainult teegi eelmine versioon nimega libhello.so.1. Programmi käivitamise katse toob kaasa vea, kuna selles süsteemis pole faili nimega libhello.so.2.

Seega peab linker kompileerimise ajal esitama teegifaili (või sümboolse lingi teegifailile) nimega lib name .so , käitamise ajal vajab laadija faili (või sümboolset linki) nimega lib name .so . x . y . Mis on nimega lib nimi .nii sellega pistmist. x . y peab ühtima kasutatud teegi soname stringiga.

Binaarsetes distributsioonides paigutatakse reeglina teegifail libhello.so.2.4.0.5 ja selle link libhello.so.2 paketti libhello ning link libhello.so , mis on vajalik ainult kompileerimiseks, koos teegi päisefailiga hello.h pakitakse paketti libhello-devel (arenduspakett sisaldab ka teegi staatilise versiooni faili libhello.a , staatilist teeki saab kasutada, ka ainult koostamisel etapp). Paketi lahti pakkimisel asuvad kõik loetletud failid ja lingid (v.a hello.h ) samas kataloogis.

Veenduge, et antud stringi soname on tõesti meie teegi failis registreeritud. Kasutame megautiliiti objdump valikuga -lk :

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


Kasulikkus objdump- võimas tööriist, mis võimaldab saada igakülgset teavet objekti või käivitatava faili sisemise sisu (ja struktuuri) kohta. Utiliidi man-leht ütleb seda objdump Esiteks on see kasulik programmeerijatele, kes loovad silumis- ja kompileerimistööriistu, mitte ainult ei kirjuta mõnda rakendusprogrammi :) Eelkõige võimalusega -d see on demonteerija. Oleme kasutanud võimalust -lk- kuvab objektifaili kohta erinevat metainfot.

Eeltoodud raamatukogu loomise näites järgisime järeleandmatult eraldi koostamise põhimõtteid. Muidugi oleks võimalik raamatukogu niimoodi koostada, ühe kõnega gcc:

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

Proovime nüüd kasutada saadud teeki:

$ gcc -Wall -c main.c
$
/usr/bin/ld: ei leia -lhello
collection2: ld tagastas 1 väljumisoleku

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

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

Nüüd on kõik õnnelikud. Käivitage loodud binaarfail:

Viga... Laadija kaebab, ei leia teeki libhello.so.2. Veenduge, et link libhello.so.2-le on tõesti käivitatavas failis registreeritud:

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

$ ln -s libhello.so.2.4.0.5 libhello.so.2
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

See töötas... Nüüd kommenteerib uusi võimalusi gcc.

Valik -Wl,-rpath,.- juba tuttav konstruktsioon, edastage linkerile võimalus -rpath argumendiga . . Kasutades -rpath programmi käivitatavas failis saate lisada täiendavaid teid, kus jagatud teegi laadija otsib teegi faile. Meie puhul tee . - teegi failide otsimine algab praegusest kataloogist.

$ objdump -p main | grep RPATH
RPATH .

Tänu sellele võimalusele ei ole programmi käivitamisel vaja keskkonnamuutujaid muuta. On selge, et kui liigutate programmi teise kataloogi ja proovite seda käivitada, siis teegi faili ei leita ja laadija kuvab veateate:

$mv peamine..
$ ../peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

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

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

Kokkuvõtteks ldd iga nõutava teegi jaoks on määratud selle soname ja teegi faili täielik tee, mis määratakse kindlaks vastavalt süsteemiseadetele.

Nüüd on aeg rääkida sellest, kuhu teegi failid süsteemis paigutatakse, kust laadija neid leida püüab ja kuidas seda protsessi hallata.

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

/lib - siia on kogutud jaotuskomplekti peamised teegid, mis on vajalikud /bin ja /sbin programmide tööks;

/usr/lib – siia salvestatakse raamatukogud, mida vajavad rakendused /usr/bin ja /usr/sbin;

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

Vaikimisi laadija otsib nendest kataloogidest teegifaile.

Lisaks ülalloetletule peab süsteemis olemas olema kataloog /usr/local/lib – seal peavad olema teegid, mille kasutaja on ise juurutanud, jättes mööda paketihaldussüsteemist (ei kuulu jaotuskomplekti). Näiteks allikatest kompileeritud teegid asuvad vaikimisi selles kataloogis (allikatest installitud programmid paigutatakse kaustadesse /usr/local/bin ja /usr/local/sbin, loomulikult räägime binaarsetest distributsioonidest). Teekide päisefailid paigutatakse sel juhul kausta /usr/local/include.

Mõnel distributsioonil (in ubuntu) laadija ei ole konfigureeritud kataloogi /usr/local/lib vaatama, seega kui kasutaja installib teegi lähtekoodist, siis süsteem seda ei näe. Selle distributsiooni tegid distributsiooni autorid spetsiaalselt selleks, et õpetada kasutajat installima tarkvara ainult paketihaldussüsteemi kaudu. Kuidas sel juhul edasi toimida, kirjeldatakse allpool.

Tegelikult ei vaata laadija teegifailide otsimise protsessi lihtsustamiseks ja kiirendamiseks iga kord, kui sellele juurde pääseb, ülaltoodud katalooge, vaid kasutab faili /etc/ld.so.cache (library) salvestatud andmebaasi vahemälu). See sisaldab teavet selle kohta, kus süsteemis antud sonamele vastav teegifail asub. Laadija, olles saanud konkreetse rakenduse jaoks vajalike teekide loendi (programmi käivitatavas failis määratud soname teekide loend), määrab iga nõutava teegi faili tee, kasutades /etc/ld.so.cache ja laadib selle mällu. Lisaks saab laadur sirvida katalooge, mis on loetletud süsteemimuutujatel LD_LIBRARY_PATH , LIBRARY_PATH ja käivitatava faili RPATH väljal (vt ülal).

Utiliiti kasutatakse raamatukogu vahemälu haldamiseks ja ajakohasena hoidmiseks. ldconfig. Kui joosta ldconfig ilma suvanditeta vaatab programm käsureal määratud katalooge, usaldusväärseid katalooge /lib ja /usr/lib , failis /etc/ld.so.conf loetletud katalooge. Iga määratud kataloogidest leitud teegifaili jaoks loetakse soname, luuakse selle põhjal sümboolne link ja värskendatakse failis /etc/ld.so.cache olevat teavet.

Teeme kindlaks, et:

$ls
hello.h libhello.so libhello.so.2.4.0.5 main.c
$
$ sudo ldconfig /full/path/to/dir/c/example
$ls
hello.h libhello.so libhello.so.2 libhello.so.2.4.0.5 main main.c
$ ./peamine
Esimene funktsioon...
Teine funktsioon...
põhifunktsioon...

Esimene kõne ldconfig salvestasime oma raamatukogu vahemällu, välistasime selle teise kõnega. Pange tähele, et koostamisel jäeti põhivariant välja -Wl,-rpath,., mille tulemusena otsis laadija vajalikke teeke ainult vahemälust.

Nüüd peaks olema selge, mida teha, kui pärast teegi allikast installimist süsteem seda ei näe. Kõigepealt tuleb lisada teegifailidega kataloogi täielik tee (vaikimisi /usr/local/lib ) faili /etc/ld.so.conf. Vorming /etc/ld.so.conf – fail sisaldab koolon-, tühiku-, tabeldus- või reavahetusega eraldatud loendit kataloogidest, millest teeke otsida. Siis helista ldconfig ilma igasuguste valikuteta, kuid superkasutaja õigustega. Kõik peaks toimima.

Noh, lõpuks räägime sellest, kuidas teekide staatilised ja dünaamilised versioonid omavahel läbi saavad. Mis on tegelik küsimus? Eespool arutledes teegifailide aktsepteeritud nimede ja asukoha üle, öeldi, et teegi staatilise ja dünaamilise versiooni failid on salvestatud samas kataloogis. Kuidas gcc teada saada, millist tüüpi raamatukogu me kasutada tahame? Vaikimisi eelistatakse dünaamilist teeki. Kui linker leiab dünaamilise teegi faili, ei kõhkle ta linkimast seda programmi käivitatava failiga:

$ls
hello.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. -tere -Wl,-rpath,.
$ ldd peamine
linux-vdso.so.1 => (0x00007fffe1bb0000)
libhello.so.2 => ./libhello.so.2 (0x00007fd50370b000)
libc.so.6 => /lib/libc.so.6 (0x00007fd50336c000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd50390f000)
$ du -h peamine
12K põhi

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

Olemas gcc -staatiline valik- juhis linkerile kasutada ainult kõigi rakenduse jaoks vajalike teekide staatilisi versioone:

$ gcc -static -o main main.o -L. - tere
$ põhifail
peamine: ELF 64-bitine LSB käivitatav fail, x86-64, versioon 1 (GNU/Linux), staatiliselt lingitud, GNU/Linux 2.6.15 jaoks, eemaldamata
$ ldd peamine
ei ole dünaamiline käivitatav fail
$ du -h peamine
728K põhi

Käivitatava faili suurus on 60 korda suurem kui eelmises näites – failis on standardkeeleteegid C. Nüüd saab meie rakendust turvaliselt kataloogist kataloogi ja isegi teistesse masinatesse üle kanda, tere raamatukogu kood on faili sees, programm on täiesti autonoomne.

Mis saab siis, kui on vaja staatiliselt linkida ainult osa kasutatud raamatukogudest? Võimalik variant lahendus on muuta teegi staatilise versiooni nimi jagatud nimest erinevaks ja rakenduse koostamisel täpsustada, millist versiooni me seekord kasutada tahame:

$ mv libhello.a libhello_s.a
$ gcc -o peamine main.o -L. -tere_s
$ ldd peamine
linux-vdso.so.1 => (0x00007fff021f5000)
libc.so.6 => /lib/libc.so.6 (0x00007fd0d0803000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd0d0ba4000)
$ du -h peamine
12K põhi

Kuna libhello teegi koodi suurus on tühine,

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

tekkiva käivitatava faili suurus on praktiliselt sama, mis dünaamilise linkimise abil loodud faili suurus.

Noh, võib-olla see on kõik. Suur tänu kõigile, kes selle lugemise lõpetasid.

Levinud on arvamus, et GCC jääb jõudluse poolest teistest kompilaatoritest maha. Selles artiklis püüame välja selgitada, milliseid põhilisi GCC-kompilaatori optimeerimisi tuleks vastuvõetava jõudluse saavutamiseks rakendada.

Millised on GCC vaikevalikud?

(1) Vaikimisi kasutab GCC optimeerimistaset "-O0". Ilmselgelt ei ole see jõudluse poolest optimaalne ja seda ei soovitata lõpptoote koostamiseks.
GCC ei tunne arhitektuuri, millel kompileerimist käitatakse, enne kui suvand ”-march=native” on möödas. Vaikimisi kasutab GCC konfigureerimisel seatud suvandeid. GCC konfiguratsiooni väljaselgitamiseks käivitage lihtsalt:

See tähendab, et GCC lisab teie valikute hulka "-march=corei7" (kui pole määratud muud arhitektuuri).
Enamik GCC kompilaatoreid x86 jaoks (põhiline 64-bitise Linuxi jaoks) lisab antud suvanditele: "-mtune=generic -march=x86-64", kuna konfiguratsioonis ei antud arhitektuurispetsiifilisi suvandeid. Kõik GCC käivitamisel edastatud valikud ja ka selle sisemised valikud saate alati teada käsuga:

Selle tulemusena kasutatakse tavaliselt:

Kasutatava arhitektuuri määramine on jõudluse jaoks oluline. Ainsaks erandiks võib pidada neid programme, kus raamatukogu funktsioonide kutsumine võtab peaaegu kogu käivitusaja. GLIBC saab käitusajal valida antud arhitektuuri jaoks optimaalse funktsiooni. Oluline on märkida, et staatilise lingi korral ei ole mõned GLIBC funktsioonid erinevate arhitektuuride jaoks versioonitud. See tähendab, et dünaamiline kokkupanek on parem, kui GLIBC funktsioonide kiirus on oluline..
(2) Vaikimisi kasutavad enamik GCC kompilaatoreid x86 jaoks 32-bitises režiimis x87 ujukomamudelit, kuna need konfigureeriti ilma "-mfpmath=sse". Ainult siis, kui GCC konfiguratsioon sisaldab "--with-mfpmath=sse":

kompilaator kasutab vaikimisi SSE mudelit. Kõigil muudel juhtudel on parem lisada 32-bitises režiimis buildile valik “-mfpmath=sse”.
Niisiis, tavaliselt kasutatakse:

Suvandi ”-mfpmath=sse” lisamine on 32-bitises režiimis oluline! Erandiks on kompilaator, mille konfiguratsioonis on "--with-mfpmath=sse".

32-bitine või 64-bitine?

32-bitist režiimi kasutatakse tavaliselt kasutatava mälumahu vähendamiseks ja sellest tulenevalt sellega töö kiirendamiseks (vahemällu paigutatakse rohkem andmeid).
64-bitises režiimis (võrreldes 32-bitisega) suureneb saadaolevate avalike registrite arv 6-lt 14-le, XMM-registrite arv 8-lt 16-le. Samuti toetavad kõik 64-bitised arhitektuurid SSE2 laiendust, seega 64-bitises režiimis pole vaja lisage valik "-mfpmath" =sse".
Arvutusülesannete jaoks on soovitatav kasutada 64-bitist režiimi ja mobiilirakenduste jaoks 32-bitist režiimi.

Kuidas saavutada maksimaalne jõudlus?

Toimivuse maksimeerimiseks pole komplekti valikuid, kuid GCC-s on palju võimalusi, mida tasub proovida. Allpool on tabel Intel Atomi ja 2. põlvkonna Intel Core i7 protsessorite soovitatavate valikute ja kasvuprognoosidega võrreldes valikuga "-O2". Prognoosid põhinevad GCC versiooni 4.7 poolt koostatud konkreetse ülesannete kogumi tulemuste geomeetrilisel keskmisel. Samuti eeldatakse, et kompilaatori konfigureerimine tehti üldise x86-64 jaoks.
Prognoos jõudluse kasvu kohta mobiilirakendused"-O2" suhtes (ainult 32-bitises režiimis, kuna see on mobiilisegmendi jaoks peamine):

Arvutusülesannete jõudluse suurenemise prognoos võrreldes "-O2"-ga (64-bitises režiimis):
-m64 -Ofast -flto ~17%
-m64 -Ofast -flto -march=native ~21%
-m64 -Ofast -flto -march=native -funroll-loops ~22%

64-bitise režiimi eelis 32-bitise ees arvutusülesannete jaoks suvanditega “-O2 -mfpmath=sse” on umbes ~5%
Kõik artiklis olevad andmed on prognoosid, mis põhinevad teatud võrdlusnäitajate kogumi tulemustel.
Allpool on artiklis kasutatud valikute kirjeldus. Täielik kirjeldus (inglise keeles): http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Optimize-Options.html"
  • "-Ofast" nagu "-O3 -ffast-math" võimaldab kõrgemal tasemel optimeerimist ja agressiivsemat optimeerimist aritmeetiliste arvutuste jaoks (nagu tõeline uuesti seostamine)
  • "-flto" moodulitevahelised optimeerimised
  • "-m32" 32-bitine režiim
  • "-mfpmath=sse" võimaldab XMM-registreid kasutada reaalses aritmeetikas (reaalviru asemel x87 režiimis)
  • "-funroll-loops" võimaldab silmuse lahtirullimist

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

Transport on materiaalse tootmise haru, mis transpordib inimesi ja kaupu. struktuuris sotsiaalne tootmine transport kuulub materiaalsete teenuste tootmise sfääri.

Märgitakse, et märkimisväärne osa logistikatoimingutest materjalivoo teel tooraine esmasest allikast lõpptarbimiseni viiakse läbi erinevate Sõiduk. Nende toimingute maksumus moodustab kuni 50% logistika kogumaksumusest.

Eesmärgi järgi eristatakse kahte peamist transpordigruppi: Ühistransport – tööstus Rahvamajandus, mis rahuldab kõigi majandusharude ja elanikkonna vajadusi kauba- ja reisijateveol. Ühistransport teenindab ringlussfääri ja elanikkonda. Seda nimetatakse sageli põhiliiniks (põhiliin on mõnes süsteemis, antud juhul sidesüsteemis, põhiliin). Ühistranspordi mõiste hõlmab raudteetransport, veetransport (mere- ja jõetransport), maantee-, õhu- ja torutransport).

Mitteühistransport - tootmissisene transport, samuti igat tüüpi sõidukid, mis kuuluvadle.

Tööstuslogistika õppeaineks on kaupade liikumise korraldamine mitteühistranspordiga. Turustuskanalite valiku probleem on lahendatud jaotuslogistika valdkonnas.

Seega on olemas järgmised peamised transpordiliigid:

raudtee

sisevee jõgi

autotööstus

õhku

torujuhe

Igal transpordiliigil on logistika juhtimise osas spetsiifilised omadused, eelised ja puudused, mis määravad selle kasutamise võimaluse logistikasüsteemis. Transpordikompleksi moodustavad erinevad transpordiliigid. Venemaa transpordikompleksi moodustavad tema territooriumil registreeritud juriidilised ja üksikisikud - ettevõtjad, kes tegelevad igat tüüpi transpordiga transpordi- ja ekspedeerimistegevusega, raudteede, teede ja rajatiste, torustike, töö projekteerimise, ehitamise, remondi ja hooldusega. seotud laevatatavate hüdroehitiste hooldusega, vee- ja hingamisteed sõnumid, hoides teaduslikud uuringud personali väljaõpe, transpordisüsteemi kuuluvad ja sõidukeid tootvad ettevõtted, samuti muud veoprotsessiga seotud tööd tegevad organisatsioonid. Venemaa TC on rohkem kui 160 tuhat km raudteed ja juurdepääsuteid, 750 tuhat km kõvakattega teid, 1,0 miljonit km merelaevaliini, 101 tuhat km sisemaad. veeteed, 800 tuhat km lennufirmasid. Ainuüksi ühistranspordiga veetakse nende side kaudu iga päev (2000. aasta andmetel) umbes 4,7 miljonit tonni kaupa, TC-s töötab üle 4 miljoni inimese ning transpordi osatähtsus riigi sisemajanduse koguproduktist on umbes 9%. Seega on transport meie riigi majanduse infrastruktuuri ja kogu sotsiaalse ja tootmispotentsiaali oluline osa.

Tabelis. 1 (4, 295) Antakse erinevate transpordiliikide võrdlevad logistilised karakteristikud.

Tabel 1 Transpordiliikide tunnused

Transpordi liik

Eelised

Puudused

raudtee

kõrge kandevõime ja läbilaskevõime. Sõltumatus kliimatingimustest, aastaajast ja kellaajast.

Transpordi kõrge regulaarsus. Suhteliselt madalad määrad; märkimisväärsed allahindlused transiitvedudele. Suur kiirus kaupade tarnimine pikkade vahemaade taha.

Piiratud arv vedajaid. Suured kapitaliinvesteeringud tootmis- ja tehnilisse baasi. Suur materjalikulu ja transpordi energiamahukus. Madal kättesaadavus müügi lõpp-punktidesse (tarbimine).

Lasti ebapiisavalt kõrge ohutus.

Mandritevahelise transpordi võimalus. Madalad transpordikulud pikkadel vahemaadel. Suur kandevõime ja kandevõime. Veonduse madal kapitalimahukus.

Piiratud transport.

Madal tarnekiirus (pikk transpordiaeg).

Sõltuvus geograafilistest, navigatsiooni- ja ilmastikutingimustest.

Vajadus luua kompleksne sadamataristu.

Sisevesi (jõgi)

Suur kandevõime süvamere jõgedel ja veehoidlates.

Madal transpordikulu. Madal kapitalimahukus.

Piiratud transport. Madal tarnekiirus.

Sõltuvus jõgede ja veehoidlate ebaühtlasest sügavusest, navigatsioonitingimustest. Hooajalisus. Ebapiisav transpordikindlus ja kauba ohutus.

autotööstus

Kõrge kättesaadavus.

Kauba kohaletoimetamise võimalus uksest ukseni

Kõrge manööverdusvõime, paindlikkus, dünaamilisus. Kõrge tarnekiirus. Võimalus kasutada erinevaid marsruute ja tarneskeeme.

Veose kõrge turvalisus. Kauba saatmise võimalus väikeste partiidena.

Madal jõudlus. Sõltuvus ilmastikust ja teeoludest. suhteliselt kõrged transpordikulud pikkadel vahemaadel.

Keskkonna ebapiisav puhtus.

Õhk

Suurim kauba kohaletoimetamise kiirus. Kõrge töökindlus.

Lasti kõrgeim ohutus.

Lühimad transporditeed.

Kõrge transpordikulu, kõrgeimad hinnad teiste transpordiliikide seas. Transpordi kõrge kapitalimahukus, materjali- ja energiamahukus. Ilmast sõltuv. Ebapiisav geograafiline juurdepääsetavus.

torujuhe

Odav. Suur jõudlus (ribalaius). Veose kõrge turvalisus. Madal kapitalimahukus.

Piiratud kaubaliigid (gaas, naftatooted, emulsioonid toored materjalid). Väikeste veetavate kaupade koguste ebapiisav saadavus.

Seega tuleb esmalt logistikajuhil otsustada, kas luua oma sõidukipark või kasutada renditransporti (avalikku või eratransporti). Alternatiivi valimisel lähtutakse tavaliselt teatud kriteeriumide süsteemist, mille hulka kuuluvad: Oma sõidukipargi loomise ja käitamise kulud. Transpordi, ekspedeerimisfirmade ja muude transpordi logistikavahendajate teenuste eest tasumise kulu Transpordi kiirus

Transpordi kvaliteet (tarnekindlus, lasti ohutus jne)

Enamikul juhtudel kasutavad tootmisettevõtted spetsialiseerunud transpordiettevõtete teenuseid.