Prednosti i nedostaci različitih oblika prijevoza. Transportna logistika transport. Međunarodni cestovni prijevoz

Da biste pravilno koristili gcc, standardni C prevodilac za Linux, trebate naučiti opcije naredbenog retka. Osim toga, gcc proširuje jezik C. Čak i ako namjeravate napisati svoj izvorni kod u ANSI standardu tog jezika, postoje neka gcc proširenja koja morate znati da biste razumjeli datoteke zaglavlja Linuxa.

Većina opcija naredbenog retka iste su kao one koje koriste C prevoditelji. Za neke opcije ne postoje standardi. U ovom poglavlju ćemo pokriti najvažnije opcije koje se koriste u svakodnevnom programiranju.

Pokušaj usklađivanja sa standardom ISO C je koristan, ali budući da je C jezik niske razine, postoje situacije u kojima standardne značajke nisu dovoljno izražajne. Postoje dva područja u kojima se gcc ekstenzije naširoko koriste: interakcija s asemblerskim kodom (ove teme su pokrivene na http://www.delorie.com/djgpp/doc/brennan/) i izgradnja zajedničkih knjižnica (vidi Poglavlje 8). Budući da su datoteke zaglavlja dio zajedničkih biblioteka, neka proširenja se također pojavljuju u datotekama zaglavlja sustava.

Naravno, postoji mnogo više proširenja koja su korisna u bilo kojoj drugoj vrsti programiranja koja stvarno mogu pomoći kod kodiranja. Više informacija o ovim proširenjima može se pronaći u gcc Texinfo dokumentaciji.

5.1. gcc opcije

gcc prihvaća mnoge opcije naredbi. Srećom, skup opcija kojih stvarno morate biti svjesni nije tako velik i u ovom poglavlju ćemo ga pogledati.

Većina opcija je ista ili slična onima drugih prevoditelja, gcc uključuje ogromnu dokumentaciju svojih opcija dostupnih preko info gcc (gcc stranica s uputama također daje ove informacije, međutim stranice s uputama se ne ažuriraju tako često kao Texinfo dokumentacija ).

-o naziv datoteke Određuje naziv izlazne datoteke. Ovo obično nije potrebno kada se kompajlira u objektnu datoteku, tj. zadana je zamjena filename.c s filename.o. Međutim, ako stvorite izvršnu datoteku, prema zadanim postavkama (zbog povijesnih razloga) ona se stvara pod imenom a.out. Ovo je također korisno kada želite smjestiti izlaznu datoteku u drugi direktorij.
-S Prevodi bez povezivanja izvorne datoteke navedene u naredbenom retku. Kao rezultat, objektna datoteka se stvara za svaku izvornu datoteku. Kada se koristi make, gcc kompajler se obično poziva za svaku objektnu datoteku; na ovaj način, u slučaju greške, lakše je pronaći koja se datoteka nije uspjela kompilirati. Međutim, ako naredbe upisujete ručno, nije neuobičajeno da se u jednom gcc pozivu specificira više datoteka. Ako može doći do dvosmislenosti prilikom navođenja više datoteka u naredbenom retku, bolje je navesti samo jednu datoteku. Na primjer, umjesto gcc -c -o a.o a.c b.c , ima smisla koristiti gcc -c -o a.o b.c .
-Dfoo Definira makronaredbe pretprocesora u naredbenom retku. Možda ćete morati odbaciti znakove koje ljuska tretira kao posebne znakove. Na primjer, kada definirate niz, trebali biste izbjegavati korištenje znakova za završetak niza " . Dva najčešća načina su "-Dfoo="bar"" i -Dfoo=\"bar\" . Prvi način radi puno bolje ako ima razmaka u nizu, jer ljuska tretira razmake na poseban način.
-I imenik Dodaje direktorij na popis direktorija za traženje uključenih datoteka.
-L imenik Dodaje direktorij na popis direktorija za traženje knjižnica, gcc će dati prednost dijeljenim bibliotekama u odnosu na statičke osim ako nije drugačije navedeno.
- fuj Veze protiv knjižnice lib foo. Osim ako nije drugačije navedeno, gcc preferira povezivanje s dijeljenim bibliotekama (lib foo .so) u odnosu na statičke (lib foo .a). Povezivač traži funkcije u svim navedenim bibliotekama redoslijedom kojim su navedene. Pretraživanje završava kada se pronađu sve potrebne funkcije.
-statički Veze samo sa statičkim bibliotekama. Vidi poglavlje 8.
-g, -ggdb Uključuje informacije o otklanjanju pogrešaka. Opcija -g uzrokuje da gcc uključi standardne informacije o otklanjanju pogrešaka. Opcija -ggdb navodi uključivanje veliki iznos informacije koje samo gdb debugger može razumjeti.
Ako je prostor na disku ograničen ili želite žrtvovati neke funkcije za brzinu veze, trebali biste koristiti -g. U ovom slučaju, možda ćete morati koristiti program za ispravljanje pogrešaka koji nije gdb. Za najpotpunije otklanjanje pogrešaka, morate navesti -ggdb. U ovom slučaju, gcc će se pripremiti što je više moguće detaljne informacije za gdb. Treba napomenuti da za razliku od većine kompilatora, gcc stavlja neke informacije o otklanjanju pogrešaka u optimizirani kod. Međutim, praćenje optimiziranog koda u programu za ispravljanje pogrešaka može biti nezgodno jer vrijeme izvođenja može skočiti i preskočiti dijelove koda za koje očekujete da će se pokrenuti. Međutim, moguće je dobiti dobra izvedba o tome kako optimizirajući prevoditelji mijenjaju način na koji se kod izvršava.
-O, -Uključeno Uzrokuje da gcc optimizira kod. Prema zadanim postavkama, gcc radi malu količinu optimizacije; kada se navede broj (n), optimizacija se provodi na određenoj razini. Najčešća razina optimizacije je 2; trenutno najviša razina optimizacije u standardnoj verziji gcc-a je 3. Preporučujemo korištenje -O2 ili -O3 ; -O3 može povećati veličinu aplikacije, pa ako je to bitno pokušajte oboje. Ako su memorija i prostor na disku važni za vašu aplikaciju, također možete koristiti opciju -Os, koja minimizira veličinu koda po cijenu povećanog vremena izvršenja. gcc omogućuje ugrađene samo kada je primijenjena barem minimalna optimizacija (-O).
-ansi Podrška u C programima za sve ANSI standarde (X3.159-1989) ili njihov ISO ekvivalent (ISO/IEC 9899:1990) (obično se naziva C89 ili rjeđe C90). Imajte na umu da ovo ne osigurava punu usklađenost sa standardom ANSI/ISO.
Opcija -ansi onemogućuje gcc proširenja koja su inače u sukobu s ANSI/ISO standardima. (Zbog činjenice da ova proširenja podržavaju mnogi drugi C kompajleri, to nije problem u praksi.) Također definira __STRICT_ANSI__ makronaredbu (kao što je opisano kasnije u ovoj knjizi) koju datoteke zaglavlja koriste za podršku usklađenosti s ANSI/ISO okoliš.
-pedantan Prikazuje sva upozorenja i pogreške koje zahtijeva jezični standard ANSI/ISO C. Ovo ne osigurava potpunu usklađenost sa standardom ANSI/ISO.
-Zid Omogućuje generiranje svih gcc upozorenja, što je obično korisno. Ali to ne uključuje opcije koje bi mogle biti korisne u određenim slučajevima. Slična razina granularnosti bit će postavljena za lint parser za vaš izvorni kod, gcc vam omogućuje da ručno uključite i isključite svako upozorenje prevoditelja. GCC priručnik detaljno opisuje sva upozorenja.
5.2. datoteke zaglavlja
5.2.1. dugo dugo

Tip long long označava da je blok memorije velik barem onoliko koliko je long . Na Intel i86 i drugim 32-bitnim platformama, long je 32 bita, dok je long long 64 bita. Na 64-bitnim platformama pokazivači i long long-ovi zauzimaju 64 bita, a long mogu uzeti 32 ili 64 bita ovisno o platformi. Dugi dugi tip podržan je u standardu C99 (ISO/IEC 9899:1999) i dugotrajno je C proširenje koje pruža gcc.

5.2.2. Ugrađene funkcije

Neki dijelovi datoteka zaglavlja Linuxa (posebno oni koji su specifični za određeni sustav) vrlo intenzivno koriste ugrađene funkcije. Brzi su poput makronaredbi (bez troškova za pozive funkcija) i pružaju sve vrste provjere valjanosti koje su dostupne u normalnom pozivu funkcije. Kod koji poziva ugrađene funkcije mora se kompilirati s omogućenom barem minimalnom optimizacijom (-O).

5.2.3. Alternativne proširene ključne riječi

U gcc-u svaka proširena ključna riječ (ključne riječi koje nisu definirane ANSI/ISO standardom) ima dvije verzije: ključna riječ i ključnu riječ okruženu s obje strane s dvije podvlake. Kada se prevodilac koristi u standardnom načinu (obično kada je omogućena opcija -ansi), normalne proširene ključne riječi se ne prepoznaju. Tako, na primjer, ključna riječ atributa u datoteci zaglavlja treba biti zapisana kao __attribute__.

5.2.4. Atributi

Ključna riječ atribut extended koristi se za prosljeđivanje više informacija o funkciji, varijabli ili deklariranom tipu gcc-u nego što to dopušta ANSI/ISO C kod. Na primjer, atribut poravnat govori gcc-u kako točno poravnati varijablu ili tip; pakirani atribut označava da se neće koristiti ispuna; noreturn specificira da se funkcija nikada ne vraća, što omogućuje gcc-u bolju optimizaciju i izbjegavanje lažnih upozorenja.

Funkcijski atributi se deklariraju njihovim dodavanjem u deklaraciju funkcije, na primjer:

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

Deklaracija atributa nalazi se između zagrada i točke sa zarezom i sadrži ključnu riječ atributa iza koje slijede atributi u dvostrukim zagradama. Ako postoji mnogo atributa, treba koristiti popis odvojen zarezima.

printm(char*, ...)

Atribut__((const,

format(printf, 1, 2)));

U ovom primjeru možete vidjeti da printm ne uzima u obzir nikakve vrijednosti osim navedenih i nema nuspojava povezanih s generiranjem koda (const), printm ukazuje da gcc treba provjeravati argumente funkcije na isti način kao printf() argumenti. Prvi argument je niz formata, a drugi argument je prvi zamjenski parametar (format).

O nekim će se atributima raspravljati kako materijal bude napredovao (na primjer, tijekom opisa izgradnje zajedničkih knjižnica u 8. poglavlju). Sveobuhvatne informacije o atributima mogu se pronaći u gcc dokumentaciji u Texinfo formatu.

S vremena na vrijeme možete pronaći sebe kako pregledavate Linux datoteke zaglavlja. Najvjerojatnije ćete pronaći niz dizajna koji nisu usklađeni s ANSI/ISO standardom. Neke od njih vrijedi pogledati. Sve konstrukcije obuhvaćene ovom knjigom detaljnije su pokrivene u gcc dokumentaciji.

S vremena na vrijeme možete pronaći sebe kako pregledavate Linux datoteke zaglavlja. Najvjerojatnije ćete pronaći niz dizajna koji nisu usklađeni s ANSI/ISO standardom. Neke od njih vrijedi pogledati. Sve konstrukcije obuhvaćene ovom knjigom detaljnije su pokrivene u gcc dokumentaciji.

Sada kada ste naučili nešto o C standardu, pogledajmo opcije koje gcc kompajler nudi kako bi se osiguralo da je u skladu sa C standardom jezika na kojem pišete. Postoje tri načina da osigurate da je vaš C kod usklađen sa standardima i da nema nedostataka: opcije koje kontroliraju kojoj verziji standarda želite biti u skladu, definicije koje kontroliraju datoteke zaglavlja i opcije upozorenja koje pokreću strožu provjeru koda.

gcc ima ogroman skup opcija, a ovdje ćemo pokriti samo one koje smatramo najvažnijima. Cjeloviti popis opcija može se pronaći na gcc online stranicama priručnika. Također ćemo ukratko raspravljati o nekim opcijama direktive #define koje se mogu koristiti; oni bi obično trebali biti navedeni u vašem izvornom kodu prije bilo kojih redaka #include ili definirani u retku za naredbe gcc. Možda ćete biti iznenađeni obiljem opcija za odabir standarda koji ćete koristiti umjesto jednostavne zastavice za prisilno korištenje trenutnog standarda. Razlog je taj što se mnogi stariji programi oslanjaju na povijesno ponašanje kompilatora i zahtijevaju značajan rad da se ažuriraju na najnovije standarde. Rijetko ćete, ako ikada, htjeti ažurirati svoj kompajler tako da prekida radni kod. Kako se standardi mijenjaju, važno je moći raditi prema određenom standardu, čak i ako to nije najnovija verzija standarda.

Čak i ako pišete mali program za osobnu upotrebu, gdje usklađenost sa standardima možda i nije toliko važna, često ima smisla uključiti dodatna gcc upozorenja kako biste natjerali kompajler da traži greške u vašem kodu prije nego što se program izvrši. To je uvijek učinkovitije nego koračati kroz kod u alatu za ispravljanje pogrešaka i pitati se gdje bi mogao biti problem. Kompajler ima mnogo opcija koje nadilaze jednostavnu provjeru standarda, kao što je mogućnost otkrivanja koda koji je u skladu sa standardom, ali vjerojatno ima upitnu semantiku. Na primjer, program može imati redoslijed izvršavanja koji dopušta pristup varijabli prije nego što se inicijalizira.

Ako trebate napisati program za zajedničku upotrebu, s obzirom na stupanj usklađenosti i tipove upozorenja kompilatora za koje mislite da su dovoljni, vrlo je važno uložiti malo više truda i natjerati vaš kod da se prevodi bez ikakvih upozorenja. Prihvatite li neka upozorenja i steknete naviku ignorirati ih, jednog dana može se pojaviti ozbiljnije upozorenje koje riskirate propustiti. Ako se vaš kod uvijek kompajlira bez poruka upozorenja, sigurno ćete primijetiti novo upozorenje. Sastavljanje koda bez upozorenja je dobra navika koju treba usvojiti.

Mogućnosti prevoditelja za standarde praćenja

Ansi je najvažnija opcija u pogledu standarda i uzrokuje da kompilator djeluje prema ISO C90 jezičnom standardu. Onemogućuje neka nestandardna gcc proširenja, onemogućuje komentare u stilu C++ (//) u C programima i omogućuje rukovanje ANSI trigrafima (nizovi od tri znaka). Osim toga, sadrži makronaredbu __STRICT_ANSI__, koja onemogućuje neka proširenja u datotekama zaglavlja koja nisu kompatibilna sa standardom. U budućim verzijama prevoditelja, prihvaćeni standard se može promijeniti.

Std= - Ova opcija pruža finiju kontrolu nad standardom koji treba koristiti pružanjem parametra koji specificira točno koji standard je potreban. Sljedeće su glavne dostupne opcije:

C89 - podržava standard C89;

Iso9899:1999 - podržava najnoviju verziju ISO standarda, C90;

Gnu89 - Podržava C89 standard, ali dopušta neka GNU proširenja i neke C99 funkcionalnosti. U verziji 4.2 gcc-a ova je opcija zadana.

Opcije za standardno praćenje u direktivama za definiranje

Postoje konstante (#defines) koje se mogu specificirati kao opcije u naredbenom retku ili kao definicije u izvornom kodu programa. Općenito ih smatramo korištenjem naredbenog retka kompilatora.

STRICT_ANSI__ Prisilno se koristi ISO C standard. Definirano kada je opcija -ansi dana u naredbenom retku prevoditelja.

POSIX_C_SOURCE=2 - Omogućuje funkcionalnost definiranu IEEE Std 1003.1 i 1003.2. Vratit ćemo se ovim standardima kasnije u ovom poglavlju.

BSD_SOURCE - Omogućuje funkcionalnost BSD sustava. Ako su u sukobu s POSIX definicijama, BSD definicije imaju prednost.

GNU_SOURCE - Omogućuje širok raspon svojstava i funkcija, uključujući GNU proširenja. Ako su ove definicije u sukobu s POSIX definicijama, potonje imaju prednost.

Opcije prevoditelja za izlaz upozorenja

Ove se opcije prenose prevoditelju iz naredbenog retka. I opet ćemo navesti samo one glavne, puni popis možete pronaći u gcc mrežnom priručniku za pomoć.

Pedantic je najmoćnija opcija čišćenja koda C. Osim što omogućuje opciju provjere prema standardu C, onemogućuje neke tradicionalne konstrukcije C koje su standardom zabranjene i čini sve GNU ekstenzije nezakonitima u odnosu na standard. Ovu bi opciju trebalo koristiti kako bi vaš C kod bio što prenosiviji.Nedostatak je taj što je prevodilac jako zabrinut za čistoću vašeg koda, pa ponekad morate razbijati glavu kako biste se riješili nekoliko preostalih upozorenja.

Wformat - provjerava ispravnost tipova argumenata funkcija obitelji printf.

Wparentheses - provjerava ima li zagrada, čak i tamo gdje nisu potrebne. Ova je opcija vrlo korisna za provjeru jesu li složene strukture inicijalizirane kako je predviđeno.

wswitch-default - Provjerava prisutnost zadane varijante u switch izjavama, što se općenito smatra dobrim stilom programiranja.

Wunused - Provjerava različite slučajeve, kao što su statičke funkcije deklarirane, ali nisu deklarirane, nekorišteni parametri, odbačeni rezultati.

Zid - Omogućuje većinu gcc tipova upozorenja, uključujući sve prethodne -W opcije (nije pokriveno samo -pedantno). Uz njegovu pomoć lako je postići čistoću programskog koda.

Bilješka

Postoji mnogo više naprednih opcija upozorenja, pogledajte gcc web stranice za sve detalje. Općenito, preporučujemo korištenje -Wall ; ovo je dobar kompromis između provjere da programski kod Visoka kvaliteta, i potrebu da kompilator ispiše puno trivijalnih upozorenja koja je teško poništiti.

GCC je uključen u svaku distribuciju linux i obično je postavljeno prema zadanim postavkama. GCC sučelje je standardno sučelje prevoditelja na UNIX platformi, ukorijenjeno u kasnim 60-im, ranim 70-im godinama prošlog stoljeća - sučelje naredbenog retka. Nemojte se bojati, u proteklom vremenu mehanizam interakcije s korisnikom je izbrušen do savršenstva mogućeg u ovom slučaju, i raditi s GCC-om (uz nekoliko dodatnih uslužnih programa i dobar uređivač teksta) lakši je nego s bilo kojim modernim vizualnim IDE-om. Autori kompleta pokušali su što je više moguće automatizirati proces kompajliranja i sastavljanja aplikacija. Korisnik poziva upravljački program gcc, interpretira proslijeđene argumente naredbenog retka (opcije i nazive datoteka) i za svaku ulaznu datoteku, u skladu s korištenim programskim jezikom, pokreće vlastiti kompajler, zatim, ako je potrebno, gcc automatski poziva asembler i povezivač (linker).

Zanimljivo, prevoditelji su jedna od rijetkih UNIX aplikacija koje brinu o ekstenzijama datoteka. Ekstenzijom GCC određuje kakva je datoteka ispred njega i što se s njom (može) raditi. Jezične izvorne datoteke C mora imati nastavak .c , u jeziku C++, alternativno, .cpp , datoteke zaglavlja u jeziku C.h , .o objektne datoteke, i tako dalje. Ako koristite pogrešno proširenje, gcc neće raditi ispravno (ako pristanete išta učiniti).

Prijeđimo na praksu. Napišimo, prevedimo i izvršimo neki jednostavan program. Nemojmo biti originalni, kao izvorna datoteka primjera programa na jeziku C Kreirajmo datoteku sa sljedećim sadržajem:

/* pozdrav.c */

#uključi

Glavni( poništiti )
{

Printf("Zdravo svijete\n" );

povratak 0 ;

Sada u imeniku c hello.c izdajemo naredbu:

$ gcc zdravo.c

Nakon nekoliko djelića sekunde, a.out datoteka će se pojaviti u direktoriju:

$ls
a.van pozdrav.c

Ovo je gotova izvršna datoteka našeg programa. Zadano gcc daje izvršnom izlazu naziv a.out (jednom davno ovo je ime značilo asemblerski izlaz).

$file a.out
a.out: ELF 64-bitni LSB izvršni, x86-64, verzija 1 (SYSV), dinamički povezan (koristi dijeljene biblioteke), za GNU/Linux 2.6.15, nije skinut

Pokrenimo rezultat softver:

$ ./a.out
Pozdrav svijete


Zašto je potrebno eksplicitno navesti stazu do datoteke u naredbi pokretanja da bi se izvršila datoteka iz trenutnog direktorija? Ako put do izvršne datoteke nije izričito naveden, ljuska, tumačeći naredbe, traži datoteku u direktorijima, čiji je popis naveden sistemskom varijablom PATH.

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/igre

Imenici na popisu odvojeni su dvotočkama. Prilikom traženja datoteka, ljuska pregledava direktorije redoslijedom kojim su navedeni. Prema zadanim postavkama, iz sigurnosnih razloga, trenutni direktorij je . nije uključeno u popis; prema tome, ljuska neće tražiti izvršne datoteke u njemu.

Zašto se ne preporučuje izrada . u PATH? Vjeruje se da će se u pravom višekorisničkom sustavu uvijek naći neka loša osoba koja će zloćudni program smjestiti u javni direktorij s nazivom izvršne datoteke koji odgovara nazivu neke naredbe koju često poziva lokalni administrator sa superuserom prava ... Zaplet će uspjeti ako . nalazi se na početku popisa imenika.


Korisnost datoteka prikazuje informacije o vrsti (sa gledišta sustava) datoteke proslijeđene u naredbenom retku, za neke vrste datoteka prikazuje sve vrste dodatne informacije u vezi sa sadržajem datoteke.

$file hello.c
hello.c: ASCII C programski tekst
$file annotation.doc
annotation.doc: CDF V2 dokument, Little Endian, OS: Windows, Verzija 5.1, Kodna stranica: 1251, Autor: MIH, Predložak: Normal.dot, Zadnje spremanje: MIH, Broj revizije: 83, Naziv aplikacije za stvaranje: Microsoft Office Word, ukupno vrijeme uređivanja: 09:37:00, zadnji ispis: čet 22. siječnja 07:31:00 2009., vrijeme/datum stvaranja: pon. 12. siječanj 07:36:00 2009., zadnje spremljeno vrijeme/datum: čet 22. siječnja 07:34:00 2009, Broj stranica: 1, Broj riječi: 3094, Broj znakova: 17637, Sigurnost: 0

To je zapravo sve što se od korisnika traži za uspješnu prijavu gcc :)

Naziv izlazne izvršne datoteke (kao i bilo koje druge datoteke koju generira gcc) može se mijenjati pomoću mogućnosti -o:

$ gcc -o zdravo zdravo.c
$ls
zdravo zdravo.c
$ ./zdravo
Pozdrav svijete


U našem primjeru funkcija main() vraća naizgled nepotrebnu vrijednost 0. U sustavima sličnim UNIX-u, uobičajeno je da se na kraju programa ljusci vrati cijeli broj - u slučaju uspješnog završetka, nula, inače bilo koji drugi. Tumač ljuske automatski će dodijeliti rezultirajuću vrijednost varijabli okruženja pod nazivom ? . Njegov sadržaj možete vidjeti koristeći echo $? :

$ ./zdravo
Pozdrav svijete
$ echo $?
0

Gore je rečeno gcc je kontrolni program dizajniran za automatizaciju procesa kompilacije. Pogledajmo što se zapravo događa kao rezultat izvršavanja naredbe gcc hello.c.

Proces kompilacije može se podijeliti u 4 glavne faze: pretprocesorska obrada, stvarna kompilacija, montaža, povezivanje (povezivanje).

Mogućnosti gcc omogućuju prekid procesa u bilo kojoj od ovih faza.

Pretprocesor priprema izvornu datoteku za kompilaciju - izrezuje komentare, dodaje sadržaj datoteka zaglavlja (pretprocesorska direktiva #include), implementira proširenje makronaredbi (simboličke konstante, predprocesorska direktiva #define).

Iskorištavati -E opcija daljnje akcije gcc možete prekinuti i pregledati sadržaj datoteke koju obrađuje predprocesor.

$ gcc -E -o zdravo.i zdravo.c
$ls
zdravo.c ​​zdravo.i
$ manje zdravo.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 "zdravo.c" 2
glavni (praznina)
{
printf("Zdravo svijete\n");
povratak 0;
}

Nakon obrade od strane predprocesora, izvorni tekst našeg programa je nabujao i dobio nečitljiv oblik. Kod koji smo nekoć utipkali vlastitim rukama sveden je na nekoliko redaka na samom kraju datoteke. Razlog je uključivanje datoteke zaglavlja standardne biblioteke C. Sama datoteka zaglavlja stdio.h sadrži puno različitih stvari i također zahtijeva uključivanje drugih datoteka zaglavlja.

Obratite pozornost na nastavak datoteke hello.i . Po dogovorima gcc ekstenzija .i odgovara datotekama s izvornim kodom u jeziku C ne zahtijeva pretprocesorsku obradu. Takve se datoteke kompajliraju zaobilazeći predprocesor:

$ gcc -o zdravo zdravo.i
$ls
zdravo zdravo.c ​​zdravo.i
$ ./zdravo
Pozdrav svijete

Nakon predprocesiranja dolazi red na kompilaciju. Prevodilac pretvara izvorni kod programa na jeziku visoke razine u kôd na asemblerskom jeziku.

Značenje riječi kompilacija je nejasno. Wikipedijanci, na primjer, smatraju, misleći na međunarodnim standardima da je kompilacija "transformacija programom prevoditelja izvorni kod bilo koji program napisan u programskom jeziku visoke razine, u jeziku bliskom strojnom kodu ili u objektnom kodu." U načelu, ova nam definicija odgovara, asemblerski jezik je stvarno bliži strojnom jeziku nego C. Ali u svakodnevnom životu, kompilacija se najčešće shvaća jednostavno kao svaka operacija koja pretvara izvorni kod programa u bilo kojem programskom jeziku u izvršni kod. To jest, proces koji uključuje sva četiri gore navedena koraka također se može nazvati kompilacijom. Slična dvosmislenost prisutna je i u ovom tekstu. S druge strane, operacija pretvaranja izvornog teksta programa u kôd asemblerskog jezika također se može označiti riječju prijevod - "transformacija programa predstavljenog na jednom od programskih jezika u program na drugom jeziku i, u izvjesnom smislu, ekvivalentan prvom."

Zaustavljanje procesa stvaranja izvršne datoteke na kraju kompilacije dopušta -S opcija:

$ gcc -S zdravo.c
$ls
zdravo.c ​​zdravo.s
$file hello.s
hello.s: ASCII asemblerski tekst programa
$ manje zdravo.s
.datoteka "hello.c"
.odjeljak .rodata
.LC0:
.string "Hello World"
.tekst
.glob glavni
.upišite main, @function
glavni:
pushl %ebp
movl %esp, %ebp
i -16 USD, posebno
subl $16, %esp
movl $.LC0, (%esp)
poziv stavlja
movl $0, %eax
napustiti
ret
.veličina glavni, .-glavni


U direktoriju se pojavila datoteka hello.s koja sadrži implementaciju programa u asemblerskom jeziku. Imajte na umu da određivanje naziva izlazne datoteke s mogućnosti -o u ovom slučaju to nije bilo potrebno gcc automatski ga je generirao zamjenom ekstenzije .c sa .s u nazivu izvorne datoteke. Za većinu osnovnih operacija gcc takvom zamjenom nastaje naziv izlazne datoteke. Ekstenzija .s standardna je za izvorne datoteke asemblerskog jezika.

Naravno, također možete dobiti izvršni kod iz datoteke hello.s:

$ gcc -o zdravo zdravo.s
$ls
zdravo zdravo.c ​​zdravo.s
$ ./zdravo
Pozdrav svijete

Sljedeća faza asemblerske operacije je prevođenje koda asemblerskog jezika u strojni kod. Rezultat operacije je objektna datoteka. Objektna datoteka sadrži blokove strojnog koda spremne za izvođenje, podatkovne blokove i popis funkcija i vanjskih varijabli definiranih u datoteci ( tablica simbola ), ali u isto vrijeme ne navodi apsolutne adrese referenci na funkcije i podatke. Objektna datoteka ne može se izvršiti izravno, ali kasnije (u fazi povezivanja) može se kombinirati s drugim objektnim datotekama (u ovom slučaju, u skladu s tablicama simbola, adrese unakrsnih referenci koje postoje između datoteka će se izračunati i popuniti ). Opcija gcc-c, zaustavlja proces na kraju koraka sklapanja:

$ gcc -c pozdrav.c
$ls
zdravo.c ​​zdravo.o
$file zdravo.o
hello.o: ELF 64-bitni LSB premjestivi, x86-64, verzija 1 (SYSV), nije skinut

Objektne datoteke koriste standardnu ​​ekstenziju .o.

Ako se primljena objektna datoteka hello.o proslijedi povezivaču, ovaj će izračunati adrese poveznica, dodati kod za pokretanje i završetak programa, kod za pozivanje funkcija biblioteke, a kao rezultat ćemo imati spreman -napravljena izvršna datoteka programa.

$ gcc -o zdravo zdravo.o
$ls
zdravo zdravo.c ​​zdravo.o
$ ./zdravo
Pozdrav svijete

Ovo što smo sada učinili (ili bolje rečeno gcc učinio za nas) i tu je sadržaj posljednje faze - povezivanje (povezivanje, povezivanje).

Pa, možda o kompilaciji i svemu tome. Sada se dotaknimo nekih, po mom mišljenju, važnih opcija. gcc.

Opcija -I put/do/direktorija/sa/zaglavljem/datotekama - dodaje navedeni direktorij na popis staza pretraživanja za datoteke zaglavlja. Imenik dodan po opciji -ja prvo pretraži, zatim se pretraga nastavlja u standardnim imenicima sustava. Ako opcije -ja višestruki, direktoriji koje navedu skeniraju se slijeva na desno kako se pojavljuju opcije.

- Zidna opcija- prikazuje upozorenja uzrokovana potencijalnim greškama u kodu koje ne sprječavaju kompilaciju programa, ali koje prema prevoditelju mogu dovesti do određenih problema tijekom njegovog izvođenja. Važna i korisna opcija, programeri gcc preporučujemo da ga uvijek koristite. Na primjer, puno će se upozorenja izdati kada se pokuša kompajlirati takva datoteka:

1 /* primjedba.c */
2
3 statički int k = 0
4 statički int l( int a);
5
6 glavni()
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 primjedba primjedba.c
$ gcc -Zid -o primjedba primjedba.c
primjedba.c:7: upozorenje: tip povrata zadano je 'int'

primjedba.c:13: upozorenje: izjava bez učinka
remark.c:9: upozorenje: neiskorištena varijabla 'a'
primjedba.c:21: upozorenje: kontrola doseže kraj funkcije koja nije prazna
primjedba.c: Na najvišoj razini:
remark.c:3: upozorenje: 'k' definirano, ali se ne koristi
primjedba.c:4: upozorenje: 'l' je deklariran kao 'statičan', ali nikad definiran
primjedba.c: U funkciji 'main':
remark.c:15: upozorenje: 'c' se koristi neinicijaliziran u ovoj funkciji
remark.c:19: upozorenje: 'p' se koristi neinicijalizirano u ovoj funkciji

Opcija -Pogreška- pretvara sva upozorenja u pogreške. Prekida proces kompilacije ako se pojavi upozorenje. Koristi se zajedno s - Zidna opcija.

$ gcc -Werror -o primjedba primjedba.c
$ gcc -Werror -Wall -o primjedba primjedba.c
cc1: upozorenja koja se tretiraju kao pogreške
primjedba.c:7: pogreška: tip povrata zadano je 'int'
primjedba.c: U funkciji 'main':
primjedba.c:13: pogreška: izjava bez učinka
remark.c:9: pogreška: neiskorištena varijabla 'a'

Opcija -g- smješta informacije potrebne za rad programa za ispravljanje pogrešaka u objekt ili izvršnu datoteku gdb. Prilikom izrade projekta u svrhu naknadnog otklanjanja pogrešaka, opcija -g moraju biti uključeni i u vrijeme kompajliranja i u vrijeme povezivanja.

Opcije -O1 , -O2 , -O3- postaviti razinu optimizacije koda koji generira prevoditelj. Kako se broj povećava, tako raste i stupanj optimizacije. Djelovanje opcija može se vidjeti u ovom primjeru.

Izvorna datoteka:

/* krug.c */

Glavni( poništiti )
{

int ja;

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

povratak ja;

Kompajliranje sa zadanom razinom optimizacije:

$ gcc -S krug.c
$ manje krugova
.datoteka "krug.c"
.tekst
.glob glavni
.upišite main, @function
glavni:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
jmp .L2
.L3:
addl $1, -4(%ebp)
.L2:
cmpl 9 USD, -4 (%ebp)
jle .L3
movl -4(%ebp),%eax
napustiti
ret
.veličina glavni, .-glavni
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits

Kompilacija s maksimalnom razinom optimizacije:

$ gcc -S -O3 krug.c
$ manje krugova
.datoteka "krug.c"
.tekst
.p2align 4.15
.glob glavni
.upišite main, @function
glavni:
pushl %ebp
movl $10, %ex
movl %esp, %ebp
popl %ebp
ret
.veličina glavni, .-glavni
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits

U drugom slučaju, u rezultirajućem kodu nema čak ni naznake bilo kakvog ciklusa. Doista, vrijednost i može se izračunati u fazi kompilacije, što je i učinjeno.

Nažalost, za stvarne projekte, razlika u performansama na različitim razinama optimizacije gotovo je neprimjetna...

Opcija -O0- poništava svaku optimizaciju koda. Opcija je potrebna u fazi otklanjanja pogrešaka aplikacije. Kao što je gore prikazano, optimizacija može dovesti do promjene u strukturi programa do neprepoznatljivosti, veza između izvršnog i izvornog koda neće biti eksplicitna, odnosno korak po korak otklanjanje pogrešaka programa neće biti moguće. Kada je opcija uključena -g, preporuča se uključiti i -O0.

-Os opcija- specificira optimizaciju ne prema učinkovitosti koda, već prema veličini rezultirajuće datoteke. Performanse programa trebale bi biti usporedive s performansama koda dobivenog kompajliranjem sa zadanom razinom optimizacije.

Opcija -march=arhitektura- specificira ciljnu arhitekturu procesora. Popis podržanih arhitektura je opsežan, na primjer, za procesore iz obitelji Intel/AMD možete postaviti i386, pentij, prescott, opteron-sse3 itd. Korisnici binarnih distribucija trebali bi imati na umu da je za ispravan rad programa s navedenom opcijom poželjno da sve uključene biblioteke budu kompilirane s istom opcijom.

O opcijama proslijeđenim povezivaču raspravljat ćemo u nastavku.

Mali dodatak:

Gore je rečeno gcc određuje vrstu (programski jezik) prenesenih datoteka prema njihovoj ekstenziji i, u skladu s pretpostavljenom vrstom (jezikom), izvršava akcije nad njima. Korisnik je dužan pratiti ekstenzije stvorenih datoteka, birajući ih prema ugovorima gcc. Zapravo gcc možete staviti datoteke s proizvoljnim imenima. gcc -x opcija omogućuje vam eksplicitno navođenje programskog jezika kompiliranih datoteka. Radnja opcije primjenjuje se na sve sljedeće datoteke navedene u naredbi (do pojavljivanja sljedeće opcije -x). Mogući argumenti opcije:

c c-zaglavlje c-cpp-izlaz

c++ c++-zaglavlje c++-cpp-izlaz

objektiv-c objektiv-c-zaglavlje objektiv-c-cpp-izlaz

objektiv-c++ objektiv-c++-zaglavlje objektiv-c++-cpp-izlaz

asembler asembler-sa-cpp

ada

f77 f77-cpp-ulaz

f95 f95-cpp-ulaz

Java

Svrha argumenata trebala bi biti jasna iz njihovog pisanja (ovdje cpp nema nikakve veze s C++, ovo je datoteka izvornog koda koju je prethodno obradio pretprocesor). Provjerimo:

$mv hello.c hello.txt
$ gcc -Zid -x c -o zdravo zdravo.txt
$ ./zdravo
Pozdrav svijete

Odvojena kompilacija

Jaka strana jezika C/C++ je mogućnost dijeljenja izvornog koda programa u nekoliko datoteka. Možete čak reći i više - mogućnost zasebne kompilacije osnova je jezika, bez nje učinkovitu upotrebu C nije zamislivo. To je programiranje s više datoteka koje vam omogućuje implementaciju na C velike projekte kao npr linux(ovdje ispod riječi linux podrazumijevaju se i kernel i sustav u cjelini). Što programeru daje zasebnu kompilaciju?

1. Omogućuje vam da kod programa (projekta) učinite čitljivijim. Izvorna datoteka za nekoliko desetaka zaslona postaje gotovo neodoljiva. Ako ga, u skladu s nekom (unaprijed dogovorenom) logikom, razbijemo na više malih fragmenata (svaki u zasebnoj datoteci), bit će puno lakše nositi se s kompleksnošću projekta.

2. Smanjuje vrijeme ponovnog sastavljanja projekta. Ako se izmjene naprave na jednoj datoteci, nema smisla ponovno kompajlirati cijeli projekt, dovoljno je ponovno kompajlirati samo ovu promijenjenu datoteku.

3. Omogućuje vam raspodjelu rada na projektu između nekoliko programera. Svaki programer kreira i otklanja pogreške svoj dio projekta, ali u svakom trenutku će biti moguće prikupiti (rekonstruirati) sve rezultirajuće razvoje u konačni proizvod.

4. Bez zasebne kompilacije ne bi bilo knjižnica. Kroz knjižnice, ponovnu upotrebu i distribuciju koda C/C++, a kod je binarni, što omogućuje, s jedne strane, pružanje programerima jednostavnog mehanizma za njegovo uključivanje u svoje programe, s druge strane, skrivanje specifičnih detalja implementacije od njih. Vrijedi li kad se radi na projektu uvijek razmišljati, a ne trebati nešto od već napravljenog nekada u budućnosti? Možda vrijedi unaprijed istaknuti i posložiti dio koda kao knjižnicu? Po mom mišljenju, ovaj pristup uvelike pojednostavljuje život i štedi puno vremena.

GCC, naravno, podržava zasebnu kompilaciju i ne zahtijeva nikakve posebne upute od korisnika. Općenito, sve je vrlo jednostavno.

Evo praktičnog primjera (iako vrlo, vrlo uvjetnog).

Skup datoteka izvornog koda:

/* main.c */

#uključi

#uključi "prvi.h"
#include "second.h"

int glavni( poništiti )
{

prvi();
drugi();

Printf("Glavna funkcija... \n" );

povratak 0 ;


/* prvi.h */

poništiti prvi( poništiti );


/* prvi.c */

#uključi

#uključi "prvi.h"

poništiti prvi( poništiti )
{

Printf("Prva funkcija... \n" );


/* sekunda.h */

poništiti drugi( poništiti );


/* drugi.c */

#uključi

#include "second.h"

poništiti drugi( poništiti )
{

Printf("Druga funkcija... \n" );

Općenito, imamo ovo:

$ls
prvi.c prvi.h glavni.c drugi.c drugi.h

Sva ova ekonomija može se sastaviti u jednu naredbu:

$ gcc -Zid -o glavni glavni.c prvi.c drugi.c
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Samo što nam to neće dati praktički nikakve bonuse, dobro, s izuzetkom strukturiranijeg i čitljivijeg koda, raspoređenog u nekoliko datoteka. Sve gore navedene prednosti pojavit će se u slučaju ovog pristupa kompilaciji:

$ gcc -Zid -c glavni.c
$ gcc -Zid -c prvi.c
$ gcc -Zid -c drugi.c
$ls
prvi.c prvi.h prvi.o glavni.c glavni.o drugi.c drugi.h drugi.o
$ gcc -o glavni glavni.o prvi.o drugi.o
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Što smo učinili? Iz svake izvorne datoteke (prevođenje s opcijom -c) je primio objektnu datoteku. Objektne datoteke zatim su povezane u konačnu izvršnu datoteku. Naravno zapovijeda gcc ima ih više, ali nitko ne sastavlja projekte ručno, za to postoje uslužni programi za asembler (najpopularniji napraviti). Pri korištenju uslužnih programa asemblera, sve gore navedene prednosti odvojenog prevođenja će se očitovati.

Postavlja se pitanje: kako povezivač uspijeva sastaviti objektne datoteke, ispravno izračunavajući adresiranje poziva? Kako on uopće zna da datoteka second.o sadrži kod funkcije second(), a kod datoteke main.o njen poziv? Ispada da je sve jednostavno - u objektnoj datoteci postoji tzv tablica simbola , koji uključuje nazive nekih kodnih pozicija (funkcija i vanjskih varijabli). Povezivač pregledava tablicu simbola svake objektne datoteke, traži uobičajene (s podudarnim imenima) pozicije, na temelju kojih izvlači zaključke o stvarnoj lokaciji koda korištenih funkcija (ili blokova podataka) i, sukladno tome, ponovno izračunava adrese poziva u izvršnoj datoteci.

Pomoću uslužnog programa možete vidjeti tablicu simbola nm.

$nm glavni.o
ti prvi
00000000 T glavni
U stavlja
U drugi
$nm prvi.o
00000000 T prvo
U stavlja
$nm sekunde.o
U stavlja
00000000 T sekunda

Poziv puts nastao je zbog upotrebe standardne bibliotečke funkcije printf() , koja je postala puts() tijekom kompajliranja.

Tablica simbola ne piše se samo u objektnu datoteku, već iu izvršnu datoteku:

$ nm glavni
08049f20d_DINAMIČKI
08049ff4d _GLOBAL_OFFSET_TABLE_
080484fc R _IO_stdin_iskorišteno
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0cd __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048538r __OKVIR_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_ručka
w __gmon_start__
080484aa T __i686.get_pc_thunk.bx
08049f0cd __početni_kraj_niza
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_kraj
080484dc T_fini
080484f8 R_fp_hw
080482b8 T _inicij
08048330 T_start
0804a014b završeno.7021
0804a00c W data_start
0804a018 b dtor_idx.7023
0804840c T prva
080483c0 t okvir_lutka
080483e4 T glavni
U stavlja@@GLIBC_2.0
08048420 T drugi

Uključivanje tablice simbola u izvršnu datoteku posebno je potrebno radi lakšeg otklanjanja pogrešaka. U principu, nije baš potrebno pokrenuti aplikaciju. Za stvarne izvršne programe, s mnogo definicija funkcija i vanjskih varijabli, uključujući hrpu različitih biblioteka, tablica simbola postaje prilično opsežna. Da biste smanjili veličinu izlazne datoteke, možete je ukloniti pomoću gcc -s opcija.

$ gcc -s -o glavni glavni.o prvi.o drugi.o
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...
$ nm glavni
nm: glavni: nema simbola

Treba napomenuti da tijekom povezivanja povezivač ne vrši nikakve provjere konteksta poziva funkcije, ne prati tip vraćene vrijednosti, niti tip i broj primljenih parametara (i nema ih gdje dobiti informacije iz). Sva provjera valjanosti poziva mora se obaviti tijekom kompajliranja. U slučaju programiranja s više datoteka, za to je potrebno koristiti mehanizam datoteka zaglavlja jezika. C.

Knjižnice

Knjižnica – u jeziku C, datoteka koja sadrži objektni kod koji se može priložiti programu pomoću biblioteke u fazi povezivanja. Zapravo, knjižnica je zbirka posebno povezanih objektnih datoteka.

Svrha knjižnica je pružiti programeru standardni mehanizam za ponovnu upotrebu koda, a mehanizam je jednostavan i pouzdan.

Sa stajališta operacijskog sustava i aplikacijskog softvera, knjižnice su statički I podijeljeno (dinamičan ).

Kod statičke knjižnice uključen je u izvršnu datoteku tijekom povezivanja potonje. Knjižnica je "hardwired" u datoteku, kod knjižnice je "spojen" s ostatkom koda datoteke. Program koji koristi statičke biblioteke postaje samostalan i može se pokrenuti na gotovo svakom računalu s odgovarajućom arhitekturom i operativnim sustavom.

Kôd zajedničke biblioteke učitava i povezuje s programskim kodom operativni sustav, na zahtjev programa tijekom njegovog izvođenja. Kod dinamičke biblioteke nije uključen u izvršnu datoteku programa; samo je poveznica na biblioteku uključena u izvršnu datoteku. Kao rezultat toga, program koji koristi dijeljene biblioteke više nije samostalan i može se uspješno izvoditi samo na sustavu u kojem su uključene biblioteke instalirane.

Paradigma zajedničke knjižnice pruža tri značajne prednosti:

1. Veličina izvršne datoteke znatno je smanjena. U sustavu koji uključuje mnoge binarne datoteke koje koriste isti kod, nema potrebe čuvati kopiju tog koda za svaku izvršnu datoteku.

2. Kod dijeljene biblioteke koji koristi nekoliko aplikacija pohranjuje se u RAM-u u jednoj instanci (zapravo, nije tako jednostavno...), što rezultira smanjenjem potrebe sustava za dostupnim RAM-om.

3. Nema potrebe za ponovnom izgradnjom svake izvršne datoteke ako su napravljene promjene u kodu zajedničke knjižnice. Promjene i ispravci koda dinamičke knjižnice automatski će se odraziti na svaki od programa koji ga koriste.

Bez paradigme dijeljene biblioteke ne bi bilo predkompiliranih (binarnih) distribucija linux(da, bez obzira na sve). Zamislite veličinu distribucije koja bi imala standardni knjižnični kod smješten u svaku binarnu datoteku. C(i sve ostale uključene biblioteke). Zamislite samo što biste morali učiniti da ažurirate sustav, nakon što ste popravili kritičnu ranjivost u jednoj od široko korištenih biblioteka...

Sada malo vježbe.

Za ilustraciju upotrijebimo skup izvornih datoteka iz prethodnog primjera. Smjestimo kod (implementaciju) funkcija first() i second() u našu domaću knjižnicu.

Linux ima sljedeću shemu imenovanja datoteka knjižnice (iako se ne poštuje uvijek) - ime datoteke knjižnice počinje prefiksom lib , nakon čega slijedi stvarni naziv knjižnice, na kraju s ekstenzijom .a ( arhiva ) - za statičku knjižnicu, .so ( zajednički objekt ) - za dijeljene (dinamičke), nakon proširenja, znamenke broja verzije navedene su kroz točku (samo za dinamičku biblioteku). Ime datoteke zaglavlja koja odgovara biblioteci (opet, u pravilu) sastoji se od naziva biblioteke (bez prefiksa i verzije) i ekstenzije .h . Na primjer: libogg.a, libogg.so.0.7.0, ogg.h.

Prvo, stvorimo i koristimo statičku biblioteku.

Funkcije first() i second() činit će sadržaj naše knjižnice libhello. Naziv datoteke knjižnice bit će libhello.a. Usporedimo datoteku zaglavlja hello.h s bibliotekom.

/* zdravo h */

poništiti prvi( poništiti );
poništiti drugi( poništiti );

Naravno, linije:

#uključi "prvi.h"


#include "second.h"

u datotekama main.c , first.c i second.c moraju se zamijeniti s:

#include "hello.h"

Pa, sada unesite sljedeći niz naredbi:

$ gcc -Zid -c prvi.c
$ gcc -Zid -c drugi.c
$ ar crs libhello.a prvi.o drugi.o
$filelibhello.a
libhello.a: trenutna ar arhiva

Kao što je već spomenuto, biblioteka je skup objektnih datoteka. S prve dvije naredbe stvorili smo ove objektne datoteke.

Zatim trebate povezati objektne datoteke u skup. Za to se koristi program za arhiviranje. ar- uslužni program "lijepi" nekoliko datoteka u jednu, u rezultirajućoj arhivi uključene su informacije potrebne za vraćanje (ekstraktiranje) svake pojedinačne datoteke (uključujući njezine atribute vlasništva, pristupa, vremena). Ne vrši se bilo kakva "kompresija" sadržaja arhive ili druga transformacija pohranjenih podataka.

c arname opcija- kreirati arhivu, ako arhiva s imenom arname ne postoji, bit će kreirana, u suprotnom će se datoteke dodati u postojeću arhivu.

r opcija- postavlja način ažuriranja arhive, ako datoteka s navedenim nazivom već postoji u arhivi, ona će biti izbrisana, a nova datoteka će biti dodana na kraj arhive.

Opcija s- dodaje (ažurira) indeks arhive. U ovom slučaju, indeks arhive je tablica u kojoj je za svaki simbolički naziv (naziv funkcije ili bloka podataka) definiran u arhiviranim datotekama, pridružen odgovarajući naziv objektne datoteke. Indeks arhive neophodan je za ubrzanje rada s bibliotekom - da biste pronašli željenu definiciju, nema potrebe pregledavati tablice simbola svih arhivskih datoteka, možete odmah otići na datoteku koja sadrži naziv koji tražite . Indeks arhive možete pogledati pomoću već poznatog uslužnog programa nm koristeći ga opcija -s(također će biti prikazane tablice simbola svih objektnih datoteka arhive):

$ nm -s libhello.a
indeks arhive:
prvi u prvom.o
drugi u drugom.o

prvo.o:
00000000 T prvo
U stavlja

drugo.o:
U stavlja
00000000 T sekunda

Za izradu indeksa arhive postoji poseban uslužni program ranlib. Biblioteka libhello.a mogla je biti kreirana ovako:

$ ar cr libhello.a prvi.o drugi.o
$ranlib libhello.a

Međutim, knjižnica će dobro funkcionirati bez indeksa arhive.

Sada upotrijebimo našu knjižnicu:

$ gcc -Zid -c glavni.c
$
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Djela...

E, sad komentari... Postoje dvije nove opcije gcc:

-l opcija imena- proslijeđeno povezivaču, ukazuje na potrebu povezivanja biblioteke imena libna s izvršnom datotekom. Poveži znači naznačiti da su te i te funkcije (vanjske varijable) definirane u toj i takvoj biblioteci. U našem primjeru, biblioteka je statična, sva simbolička imena odnosit će se na kod koji se nalazi izravno u izvršnoj datoteci. Obratite pozornost na opcije -l naziv knjižnice daje se kao naziv bez prefiksa lib.

Opcija -L /put/do/direktorija/sa/bibliotekama - proslijeđen povezivaču, navodi stazu do direktorija koji sadrži povezane knjižnice. U našem slučaju, točka . , povezivač će prvo tražiti biblioteke u trenutnom direktoriju, zatim u direktorijima definiranim u sustavu.

Ovdje je potrebno napraviti malu napomenu. Činjenica je da za niz opcija gcc bitan je redoslijed kojim se pojavljuju u naredbenom retku. Ovo je način na koji povezivač traži kod koji odgovara nazivima navedenim u tablici simbola datoteke u bibliotekama navedenim u naredbenom retku nakon naziv ove datoteke. Linker zanemaruje sadržaj biblioteka navedenih prije naziva datoteke:

$ gcc -Zid -c glavni.c
$ gcc -o glavni -L. -lpozdrav glavni.o
main.o: U funkciji `main":
main.c:(.text+0xa): nedefinirana referenca na `prvi'
main.c:(.text+0xf): nedefinirana referenca na `drugi'

$ gcc -o glavni glavni.o -L. - zdravo
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Ovakvo ponašanje gcc zbog želje programera da korisniku pruže mogućnost kombiniranja datoteka s bibliotekama na različite načine, koriste imena koja se križaju ... Po mom mišljenju, ako je moguće, bolje je ne zamarati se time. Općenito, biblioteke veza trebale bi biti navedene nakon naziva datoteke koja ih upućuje.

postoji alternativni način određivanje lokacije knjižnica u sustavu. Ovisno o distribuciji, varijabla okoline LD_LIBRARY_PATH ili LIBRARY_PATH može pohraniti popis direktorija odvojen dvotočkom u kojima bi povezivač trebao tražiti biblioteke. U pravilu, prema zadanim postavkama, ova varijabla uopće nije definirana, ali ništa ne sprječava njezino stvaranje:

$ echo $LD_LIBRARY_PATH

/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/../../../../i686-pc-linux-gnu/bin/ld: ne mogu pronaći -lhello
collect2: ld izašao s povratnim kodom 1
$ izvoz LIBRARY_PATH=.
$ gcc -o glavni glavni.o -lzdravo
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Manipulacije s varijablama okoline korisne su pri stvaranju i otklanjanju pogrešaka vlastitih biblioteka, kao i ako postane potrebno povezati neku nestandardnu ​​(zastarjelu, ažuriranu, promijenjenu - općenito različitu od one uključene u distribucijski komplet) dijeljenu biblioteku s aplikacijom.

Sada stvorimo i koristimo dinamičku biblioteku.

Skup izvornih datoteka ostaje nepromijenjen. Unosimo naredbe, vidimo što se dogodilo, čitamo komentare:

$ gcc -Zid -fPIC -c prvo.c
$ gcc -Zid -fPIC -c drugi.c
$ gcc -shared -o libhello.so.2.4.0.5 -Wl,-soname,libhello.so.2 prvi.o drugi.o

Što ste dobili kao rezultat?

$ datoteka libhello.so.2.4.0.5
libhello.so.2.4.0.5: ELF 64-bitni LSB zajednički objekt, x86-64, verzija 1 (SYSV), dinamički povezan, nije ogoljen

Datoteka libhello.so.2.4.0.5 je naša dijeljena biblioteka. Razgovarajmo o tome kako ga koristiti u nastavku.

Sada komentari:

Opcija -fPIC- zahtijeva od prevoditelja, prilikom stvaranja objektnih datoteka, generiranje položaj neovisni kod (PIC - Position Independent Code ), njegova glavna razlika je u načinu na koji su adrese prikazane. Umjesto određivanja fiksnih (statičkih) pozicija, sve adrese se izračunavaju na temelju odmaka navedenih u globalna offset tablica (globalna offset tablica - GOT ). Format koda neovisan o poziciji omogućuje vam povezivanje izvršnih modula s kodom glavnog programa u trenutku njegovog učitavanja. Sukladno tome, glavna svrha koda neovisnog o poziciji je stvaranje dinamičkih (dijeljenih) knjižnica.

- zajednička opcija- ukazuje gcc, da kao rezultat toga ne bi trebala biti izgrađena izvršna datoteka, već zajednički objekt - dinamička biblioteka.

Opcija -Wl,-soname,libhello.so.2- setovi soname knjižnicama. O soname ćemo detaljno govoriti u sljedećem odlomku. Raspravljajmo sada o formatu opcije. Ova čudna, na prvi pogled, konstrukcija sa zarezima namijenjena je izravnoj interakciji između korisnika i povezivača. Tijekom kompilacije gcc poziva povezivač automatski, automatski, prema vlastitom nahođenju, gcc prenosi mu opcije potrebne za uspješan završetak posla. Ako korisnik treba sam intervenirati u procesu povezivanja, može koristiti posebnu opciju gcc -Wl, -opcija, vrijednost1, vrijednost2 .... Što znači prijeći na povezivač ( -Wl) opcija -opcija s argumentima vrijednost1, vrijednost2 i tako dalje. U našem slučaju, povezivač je dobio opciju -ime s argumentom libhello.so.2.

Sada o imenu. Kod stvaranja i distribucije knjižnica javlja se problem kompatibilnosti i kontrole verzija. Kako bi sustav, posebno dinamički učitavač biblioteke, imao ideju o tome koja je verzija biblioteke korištena prilikom kompajliranja aplikacije i, shodno tome, neophodna za njezin uspješan rad, osiguran je poseban identifikator - soname , smješten u samu datoteku knjižnice i u izvršnu datoteku aplikacije. Identifikator soname je niz koji sadrži naziv biblioteke s prefiksom lib , točku, ekstenziju so, ponovno točku i jednu ili dvije (točkom odvojene) znamenke verzije biblioteke, ime lib .so. x . y . To jest, soname odgovara imenu datoteke biblioteke do prve ili druge znamenke broja verzije. Neka ime izvršne datoteke naše biblioteke bude libhello.so.2.4.0.5 , tada bi ime biblioteke moglo biti libhello.so.2 . Prilikom promjene sučelja knjižnice, mora se promijeniti i njezino ime! Svaka izmjena koda koja uzrokuje nekompatibilnost s prethodnim izdanjima mora biti popraćena novim imenom.

Kako to sve funkcionira? Neka je za uspješno izvršavanje neke aplikacije potrebna knjižnica s imenom hello, neka postoji u sustavu, a naziv datoteke knjižnice je libhello.so.2.4.0.5 , a ime knjižnice koja je zapisana u njoj je libhello .dakle.2 . U fazi sastavljanja aplikacije, povezivač, prema opciji - zdravo, pretražit će sustav za datoteku pod nazivom libhello.so. Na stvarnom sustavu, libhello.so je simbolička veza na datoteku libhello.so.2.4.0.5. Nakon što pristupi datoteci biblioteke, povezivač čita vrijednost soname registriranu u njoj i, između ostalog, stavlja je u izvršnu datoteku aplikacije. Kada se aplikacija pokrene, dinamički učitavač biblioteke primit će zahtjev za uključivanje biblioteke s imenom soname pročitanim iz izvršne datoteke i pokušat će pronaći biblioteku na sustavu čiji naziv datoteke odgovara imenu sonamena. To jest, učitavač će pokušati pronaći datoteku libhello.so.2. Ako je sustav ispravno konfiguriran, trebao bi sadržavati simboličku vezu libhello.so.2 na datoteku libhello.so.2.4.0.5 , učitavač će dobiti pristup traženoj biblioteci i tada će bez oklijevanja (i bez provjere bilo čega drugog) povežite ga s aplikacijom. Sada zamislite da smo ovako kompajliranu aplikaciju prenijeli na drugi sustav gdje je postavljena samo prethodna verzija biblioteke sa imenom libhello.so.1. Pokušaj pokretanja programa rezultirat će pogreškom jer na ovom sustavu ne postoji datoteka pod nazivom libhello.so.2.

Dakle, u vrijeme kompajliranja povezivač treba pružiti datoteku biblioteke (ili simboličku vezu na datoteku biblioteke) koja se zove ime lib .so , u vrijeme izvođenja učitavač treba datoteku (ili simboličku vezu) koja se zove ime lib .so . x . y . Što znači naziv lib name .so ima veze s tim. x . y mora odgovarati nizu soname korištene biblioteke.

U binarnim distribucijama, u pravilu će datoteka biblioteke libhello.so.2.4.0.5 i poveznica na nju libhello.so.2 biti smještena u libhello paket, a veza libhello.so , koja je potrebna samo za kompilaciju, zajedno s datotekom zaglavlja biblioteke hello.h bit će zapakirana u libhello-devel paket (devel paket će također sadržavati datoteku statičke verzije biblioteke libhello.a , statička biblioteka se može koristiti, također samo pri kompilaciji pozornica). Prilikom raspakiranja paketa, sve navedene datoteke i veze (osim hello.h ) bit će u istom direktoriju.

Provjerimo da je dani niz soname stvarno registriran u datoteci naše knjižnice. Upotrijebimo mega uslužni program objdump s opcijom -str :

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


Korisnost objdump- moćan alat koji vam omogućuje da dobijete sveobuhvatne informacije o unutarnjem sadržaju (i strukturi) objekta ili izvršne datoteke. Stranica s uputama za pomoćni program to kaže objdump Prije svega, bit će koristan programerima koji stvaraju alate za ispravljanje pogrešaka i kompilaciju, a ne samo pišu neke aplikacijske programe :) Konkretno, s opcijom -d to je rastavljač. Iskoristili smo opciju -str- prikaz različitih meta-informacija o objektnoj datoteci.

U gornjem primjeru stvaranja biblioteke neumoljivo smo slijedili načela odvojenog sastavljanja. Naravno, biblioteku bi bilo moguće kompajlirati i ovako, jednim pozivom gcc:

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

Pokušajmo sada upotrijebiti dobivenu biblioteku:

$ gcc -Zid -c glavni.c
$
/usr/bin/ld: ne može pronaći -lhello
collect2: ld je vratio 1 izlazni status

Povezivač psuje. Zapamtite što je gore rečeno o simboličkim vezama. Stvorite libhello.so i pokušajte ponovno:

$ ln -s libhello.so.2.4.0.5 libhello.so
$ gcc -o glavni glavni.o -L. -lzdravo -Wl,-rpath,.

Sada su svi sretni. Pokrenite generiranu binarnu datoteku:

Greška... Učitavač se žali, ne može pronaći biblioteku libhello.so.2. Provjerimo da je poveznica na libhello.so.2 stvarno registrirana u izvršnoj datoteci:

$ objdump -p glavni | grep POTREBAN
libhello.so.2
libc.so.6

$ ln -s libhello.so.2.4.0.5 libhello.so.2
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Uspjelo je... Sada komentira nove opcije gcc.

Opcija -Wl,-rpath,.- već poznata konstrukcija, proslijedite opciju povezivaču -rpath s argumentom . . Pomoću -rpath u izvršnoj datoteci programa možete dodati dodatne staze gdje će učitavač zajedničke biblioteke tražiti datoteke biblioteke. U našem slučaju, put . - traženje datoteka knjižnice počet će iz trenutnog direktorija.

$ objdump -p glavni | grep RPATH
RPATH .

Zahvaljujući ovoj opciji, prilikom pokretanja programa nema potrebe mijenjati varijable okoline. Jasno je da ako premjestite program u drugi direktorij i pokušate ga pokrenuti, datoteka knjižnice neće biti pronađena i program za učitavanje će prikazati poruku o pogrešci:

$mv glavni..
$ ../glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Pomoću uslužnog programa također možete saznati koje zajedničke knjižnice aplikacija treba ldd:

$ ldd glavni
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)

U zaključku ldd za svaku potrebnu biblioteku naveden je njen naziv i puna staza do datoteke biblioteke, određena u skladu s postavkama sustava.

Sada je vrijeme da razgovaramo o tome gdje bi knjižnične datoteke trebale biti smještene u sustavu, gdje ih učitavač pokušava pronaći i kako upravljati ovim procesom.

Prema dogovorima FHS (Standard hijerarhije datotečnog sustava) sustav mora imati dva (barem) direktorija za pohranu datoteka knjižnice:

/lib - ovdje su prikupljene glavne biblioteke distribucijskog kompleta, potrebne za rad programa iz /bin i /sbin ;

/usr/lib - ovdje su pohranjene biblioteke potrebne aplikacijama iz /usr/bin i /usr/sbin;

Datoteke zaglavlja koje odgovaraju bibliotekama moraju biti u direktoriju /usr/include.

Zadani učitavač tražit će datoteke biblioteke u tim direktorijima.

Uz one gore navedene, /usr/local/lib direktorij mora biti prisutan u sustavu - moraju postojati biblioteke koje korisnik sam postavlja, zaobilazeći sustav za upravljanje paketima (nije uključeno u distribucijski komplet). Na primjer, biblioteke kompajlirane iz izvora bit će u ovom direktoriju prema zadanim postavkama (programi instalirani iz izvora bit će smješteni u /usr/local/bin i /usr/local/sbin , naravno, govorimo o binarnim distribucijama). Datoteke zaglavlja knjižnica u ovom će slučaju biti smještene u /usr/local/include.

Na nekim distribucijama (in ubuntu) učitavač nije konfiguriran za pregled direktorija /usr/local/lib, tako da ako korisnik instalira biblioteku iz izvora, sustav je neće vidjeti. Ovu su distribuciju napravili autori distribucije posebno kako bi naučili korisnika instalirati softver samo kroz sustav za upravljanje paketima. Kako postupiti u ovom slučaju bit će opisano u nastavku.

Zapravo, kako bi se pojednostavio i ubrzao proces pronalaženja datoteka knjižnice, učitavač ne gleda gore navedene direktorije svaki put kada mu se pristupi, već koristi bazu podataka pohranjenu u datoteci /etc/ld.so.cache (biblioteka predmemorija). Ovo sadrži informacije o tome gdje se u sustavu nalazi datoteka knjižnice koja odgovara danom imenu. Učitavač, nakon što je primio popis biblioteka koje zahtijeva određena aplikacija (popis soname biblioteka navedenih u izvršnoj datoteci programa), određuje stazu do datoteke svake potrebne biblioteke koristeći /etc/ld.so.cache i učitava je u memoriju. Dodatno, učitavač može pregledavati direktorije navedene u sistemskim varijablama LD_LIBRARY_PATH, LIBRARY_PATH iu RPATH polju izvršne datoteke (vidi gore).

Uslužni program se koristi za upravljanje i održavanje predmemorije knjižnice ažurnom. ldconfig. Ako trči ldconfig bez ikakvih opcija, program će pogledati direktorije navedene u naredbenom retku, pouzdane direktorije /lib i /usr/lib, direktorije navedene u datoteci /etc/ld.so.conf. Za svaku datoteku biblioteke pronađenu u navedenim direktorijima, ime će biti pročitano, simbolička veza temeljena na imenu imena bit će kreirana, a informacije u /etc/ld.so.cache će se ažurirati.

Uvjerimo se da:

$ls
hello.h libhello.so libhello.so.2.4.0.5 main.c
$
$ sudo ldconfig /puni/put/do/dir/c/primjer
$ls
hello.h libhello.so libhello.so.2 libhello.so.2.4.0.5 main main.c
$ ./glavni
Prva funkcija...
Druga funkcija...
glavna funkcija...

Prvi poziv ldconfig spremili smo našu knjižnicu u predmemoriju, isključili je s drugim pozivom. Imajte na umu da je glavna opcija izostavljena prilikom kompajliranja -Wl,-rpath,., kao rezultat toga, učitavač je tražio potrebne biblioteke samo u predmemoriji.

Sada bi trebalo biti jasno što učiniti ako nakon instaliranja biblioteke iz izvora sustav to ne vidi. Prije svega, trebate dodati puni put do direktorija s datotekama biblioteke (prema zadanim postavkama /usr/local/lib ) u datoteku /etc/ld.so.conf. Format /etc/ld.so.conf - datoteka sadrži dvotočkom, razmakom, tabulatorom ili novim redom odvojen popis direktorija u kojima se traže biblioteke. Onda nazovi ldconfig bez ikakvih opcija, ali sa superuser pravima. Sve bi trebalo raditi.

Pa, na kraju, razgovarajmo o tome kako se statične i dinamičke verzije knjižnica slažu. Što je zapravo pitanje? Gore, kada se raspravljalo o prihvaćenim nazivima i lokaciji knjižničnih datoteka, rečeno je da su datoteke statičke i dinamičke verzije knjižnice pohranjene u istom direktoriju. Kako gcc saznati koju vrstu knjižnice želimo koristiti? Prema zadanim postavkama prednost se daje dinamičkoj biblioteci. Ako povezivač pronađe datoteku dinamičke biblioteke, ne oklijeva je povezati s izvršnom datotekom programa:

$ls
hello.h libhello.a libhello.so libhello.so.2 libhello.so.2.4.0.5 main.c
$ gcc -Zid -c glavni.c
$ gcc -o glavni glavni.o -L. -lzdravo -Wl,-rpath,.
$ ldd glavni
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 glavni
12K glavni

Obratite pozornost na veličinu izvršne datoteke programa. To je minimalno moguće. Sve korištene biblioteke su dinamički povezane.

postoji gcc -statička opcija- uputa povezivaču da koristi samo statične verzije svih biblioteka potrebnih za aplikaciju:

$ gcc -statički -o glavni glavni.o -L. - zdravo
$ glavna datoteka
glavni: ELF 64-bitni LSB izvršni, x86-64, verzija 1 (GNU/Linux), statički povezan, za GNU/Linux 2.6.15, nije skinut
$ ldd glavni
nije dinamička izvršna datoteka
$ du -h glavni
728K glavni

Veličina izvršne datoteke je 60 puta veća nego u prethodnom primjeru - biblioteke standardnog jezika uključene su u datoteku C. Sada se naša aplikacija može sigurno prenijeti iz direktorija u direktorij, pa čak i na druga računala, pozdravni kod knjižnice je unutar datoteke, program je potpuno autonoman.

Što ako je potrebno statički povezati samo dio korištenih biblioteka? Moguća varijanta rješenje je da se naziv statičke verzije biblioteke razlikuje od naziva dijeljene, a kod kompajliranja aplikacije odredimo koju verziju želimo ovaj put koristiti:

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

Budući da je veličina koda knjižnice libhello zanemariva,

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

veličina rezultirajuće izvršne datoteke praktički je ista kao veličina datoteke stvorene pomoću dinamičkog povezivanja.

Pa, možda je to sve. Veliko hvala svima koji su završili čitanje na ovom mjestu.

Uvriježeno je mišljenje da GCC zaostaje za drugim kompajlerima u pogledu izvedbe. U ovom ćemo članku pokušati otkriti koje osnovne optimizacije GCC prevoditelja treba primijeniti da bi se postigla prihvatljiva izvedba.

Koje su zadane opcije u GCC-u?

(1) Prema zadanim postavkama GCC koristi razinu optimizacije "-O0". Jasno je da nije optimalan u smislu izvedbe i ne preporučuje se za sastavljanje konačnog proizvoda.
GCC ne prepoznaje arhitekturu na kojoj se izvodi kompilacija dok se ne prođe opcija ”-march=native”. Prema zadanim postavkama, GCC koristi opciju postavljenu tijekom konfiguracije. Da saznate GCC konfiguraciju, samo pokrenite:

To znači da će GCC dodati "-march=corei7" vašim opcijama (osim ako nije navedena druga arhitektura).
Većina GCC kompajlera za x86 (osnovni za 64-bitni Linux) dodaje: “-mtune=generic -march=x86-64” danim opcijama, budući da u konfiguraciji nisu dane opcije specifične za arhitekturu. Uvijek možete saznati sve opcije koje ste prošli prilikom pokretanja GCC-a, kao i njegove interne opcije, pomoću naredbe:

Kao rezultat toga, obično se koriste:

Određivanje arhitekture za korištenje važno je za izvedbu. Jedini izuzetak mogu se smatrati oni programi kod kojih poziv funkcija knjižnice traje gotovo cijelo vrijeme pokretanja. GLIBC može odabrati optimalnu funkciju za danu arhitekturu tijekom izvođenja. Važno je napomenuti da kada su statički povezane, neke GLIBC funkcije nemaju verziju za različite arhitekture. Odnosno, dinamička montaža je bolja ako je važna brzina GLIBC funkcija..
(2) Prema zadanim postavkama, većina GCC kompajlera za x86 u 32-bitnom načinu rada koristi x87 model s pomičnim zarezom, jer su konfigurirani bez "-mfpmath=sse". Samo ako GCC konfiguracija sadrži "--with-mfpmath=sse":

kompajler će prema zadanim postavkama koristiti SSE model. U svim drugim slučajevima, bolje je dodati opciju “-mfpmath=sse” u izgradnju u 32-bitnom načinu rada.
Dakle, uobičajeno korišteno:

Dodavanje opcije ”-mfpmath=sse” važno je u 32-bitnom načinu! Izuzetak je kompajler koji u svojoj konfiguraciji ima "--with-mfpmath=sse".

32-bitni način ili 64-bitni?

32-bitni način rada obično se koristi za smanjenje količine korištene memorije i, kao rezultat toga, za ubrzavanje rada s njim (više podataka se stavlja u predmemoriju).
U 64-bitnom načinu rada (u usporedbi s 32-bitnim) broj dostupnih javnih registara povećava se sa 6 na 14, XMM registara s 8 na 16. Također, sve 64-bitne arhitekture podržavaju SSE2 proširenje, tako da u 64-bitnom načinu rada ne trebate dodajte opciju “-mfpmath” =sse".
Preporuča se korištenje 64-bitnog načina rada za računalne zadatke i 32-bitnog načina rada za mobilne aplikacije.

Kako postići maksimalne performanse?

Ne postoji set opcija za maksimiziranje performansi, ali postoje mnoge opcije u GCC-u koje vrijedi isprobati. Ispod je tablica s preporučenim opcijama i prognozama rasta za Intel Atom i 2. generaciju Intel Core i7 procesora u odnosu na opciju "-O2". Predviđanja se temelje na geometrijskoj sredini rezultata određenog skupa zadataka koje je sastavio GCC verzija 4.7. Također pretpostavlja da je konfiguracija kompajlera napravljena za x86-64 generic.
Prognoza povećanja performansi za mobilne aplikacije u odnosu na "-O2" (samo u 32-bitnom načinu, budući da je glavni za mobilni segment):

Predviđanje povećanja performansi računalnih zadataka u odnosu na "-O2" (u 64-bitnom načinu):
-m64 -Ofast -flto ~17%
-m64 -Ofast -flto -march=domaći ~21%
-m64 -Ofast -flto -march=native -funroll-loops ~22%

Prednost 64-bitnog načina rada u odnosu na 32-bitni za računalne zadatke s opcijama “-O2 -mfpmath=sse” je oko ~5%
Svi podaci u članku su predviđanje temeljeno na rezultatima određenog skupa mjerila.
Ispod je opis opcija korištenih u članku. Puni opis (na engleskom): http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Optimize-Options.html"
  • "-Ofast" poput "-O3 -ffast-math" omogućuje višu razinu optimizacija i agresivnije optimizacije za aritmetičke izračune (poput stvarne reasocijacije)
  • "-flto" optimizacije između modula
  • "-m32" 32-bitni način rada
  • "-mfpmath=sse" omogućuje korištenje XMM registara u stvarnoj aritmetici (umjesto stvarnog stoga u x87 modu)
  • "-funroll-loops" omogućuje odmotavanje petlje

Transportna logistika(analiza različitih vrsta transporta: prednosti, nedostaci)

Promet je grana materijalne proizvodnje koja prevozi ljude i robu. u strukturi društvena proizvodnja promet pripada sferi proizvodnje materijalnih usluga.

Napominje se da se značajan dio logističkih operacija na putu protoka materijala od primarnog izvora sirovina do konačne potrošnje odvija pomoću različitih Vozilo. Trošak ovih operacija iznosi do 50% ukupnih troškova logistike.

Prema namjeni razlikuju se dvije glavne skupine prometa: Javni promet – industrija Nacionalna ekonomija, koji zadovoljava potrebe svih grana gospodarstva i stanovništva u prijevozu robe i putnika. Javni prijevoz služi sferi prometa i stanovništvu. Često se naziva i glavna linija (glavna linija je glavna, glavna linija u nekom sustavu, u ovom slučaju, u komunikacijskom sustavu). Pojam javnog prijevoza obuhvaća željeznički promet, vodeni promet (pomorski i riječni), cestovni, zračni i cjevovodni promet).

Nejavni promet - unutarproizvodni promet, kao i vozila svih vrsta koja pripadaju neprometnim organizacijama.

Organizacija kretanja roba nejavnim prometom predmet je proučavanja industrijske logistike. Problem izbora distribucijskih kanala rješava se u području distribucijske logistike.

Dakle, postoje sljedeći glavni načini prijevoza:

željeznička pruga

rijeka unutarnjih voda

automobilski

zrak

cjevovod

Svaki od vidova transporta ima specifičnosti u smislu upravljanja logistikom, prednosti i nedostatke koji određuju mogućnost njegove primjene u logističkom sustavu. Prometni kompleks čine različite vrste prometa. Prometni kompleks Rusije čine pravne i fizičke osobe registrirane na njezinom teritoriju - poduzetnici koji obavljaju prijevoz i špeditersku djelatnost na svim vrstama prometa, projektiranje, izgradnju, popravak i održavanje željeznica, cesta i objekata na njima, cjevovoda, radova vezano uz održavanje plovnih hidrotehničkih građevina, voda i dišnih putova poruke, držanje znanstveno istraživanje i osposobljavanje kadrova, poduzeća koja su dio prometnog sustava i proizvode vozila, kao i organizacije koje obavljaju druge poslove vezane uz prometni proces. TC Rusije je više od 160 tisuća km glavnih željezničkih i pristupnih cesta, 750 tisuća km asfaltiranih cesta, 1,0 milijun km pomorskih linija, 101 tisuća km kopnenih vodeni putovi, 800 tisuća km zračnih linija. Samo javnim prijevozom ovim se komunikacijama dnevno (prema podacima za 2000.) preveze oko 4,7 milijuna tona tereta, u TK radi više od 4 milijuna ljudi, a udio prometa u bruto društvenom proizvodu zemlje iznosi oko 9%. Dakle, promet je bitan dio infrastrukture gospodarstva i cjelokupnog društvenog i proizvodnog potencijala naše zemlje.

U tablici. 1 (4, 295) Dane su usporedne logističke karakteristike različitih oblika transporta.

Tablica 1. Karakteristike načina prijevoza

Vrsta prijevoza

Prednosti

Mane

željeznička pruga

velika nosivost i propusnost. Neovisnost o klimatskim uvjetima, godišnjem dobu i danu.

Visoka redovitost prijevoza. Relativno niske stope; značajni popusti za tranzitne pošiljke. Velika brzina dostava robe na velike udaljenosti.

Ograničen broj nosača. Velika kapitalna ulaganja u proizvodnu i tehničku bazu. Velika potrošnja materijala i energetski intenzitet transporta. Slaba dostupnost krajnjim prodajnim mjestima (potrošnja).

Nedovoljno visoka sigurnost tereta.

Mogućnost interkontinentalnog prijevoza. Niska cijena prijevoza na velike udaljenosti. Visoka nosivost i nosivost. Niska kapitalna intenzivnost transporta.

Ograničen prijevoz.

Mala brzina isporuke (dugo vrijeme prijevoza).

Ovisnost o geografskim, navigacijskim i vremenskim uvjetima.

Potreba za stvaranjem složene lučke infrastrukture.

Unutarnja voda (rijeka)

Visoka nosivost na dubokim rijekama i akumulacijama.

Niska cijena prijevoza. Niska kapitalna intenzivnost.

Ograničen prijevoz. Mala brzina isporuke.

Ovisnost o neujednačenim dubinama rijeka i akumulacija, navigacijskim uvjetima. Sezonalnost. Nedovoljna pouzdanost prijevoza i sigurnost tereta.

automobilski

Visoka dostupnost.

Mogućnost dostave tereta od vrata do vrata

Visoka manevarska sposobnost, fleksibilnost, dinamičnost. Velika brzina isporuke. Mogućnost korištenja različitih ruta i shema dostave.

Visoka sigurnost tereta. Mogućnost slanja tereta u malim serijama.

Niska izvedba. Ovisnost o vremenu i uvjetima na cesti. relativno visoka cijena prijevoza na velike udaljenosti.

Nedovoljna čistoća okoliša.

Zrak

Najveća brzina isporuke tereta. Visoka pouzdanost.

Najveća sigurnost tereta.

Najkraće transportne rute.

Visoki troškovi prijevoza, najviše cijene među ostalim načinima prijevoza. Visoka kapitalna, materijalna i energetska intenzivnost transporta. Ovisno o vremenskim prilikama. Nedovoljna geografska dostupnost.

cjevovod

Niska cijena. Visoke performanse (propusnost). Visoka sigurnost tereta. Niska kapitalna intenzivnost.

Ograničene vrste tereta (plin, naftni proizvodi, emulzije sirovine). Nedovoljna dostupnost malih količina prevezene robe.

Dakle, prije svega, voditelj logistike mora odlučiti hoće li stvoriti vlastiti vozni park ili će koristiti unajmljeni prijevoz (javni ili privatni). Pri odabiru alternative obično polaze od određenog sustava kriterija koji uključuju: Trošak stvaranja i rada vlastite flote vozila. Troškovi plaćanja usluga prijevoza, špeditera i drugih logističkih posrednika u prijevozu Brzina prijevoza

Kvaliteta prijevoza (pouzdanost isporuke, sigurnost tereta, itd.)

U većini slučajeva proizvodne tvrtke pribjegavaju uslugama specijaliziranih prijevozničkih tvrtki.