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

Da biste pravilno koristili gcc, standardni Linux C kompajler, morate naučiti o opcijama naredbenog retka. Uz to, gcc proširuje jezik C. Čak i ako namjeravate napisati izvorni kod poštujući ANSI standard ovog jezika, neka proširenja gcc jednostavno je potrebno znati kako bi se razumjele datoteke zaglavlja Linuxa.

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

Korisno je nastojati se pridržavati se norme ISO C, ali s obzirom na činjenicu da je jezik C na niskoj razini, postoje situacije u kojima standardna sredstva nisu dovoljno izražajna. Dva su područja u kojima se gcc proširenja široko koriste: interakcija s kodom sklopa (za ove teme pogledajte http://www.delorie.com/djgpp/doc/brennan/) i izgradnja zajedničkih knjižnica (vidi poglavlje 8). Budući da su datoteke zaglavlja dio dijeljenih knjižnica, neka se proširenja pojavljuju i u datotekama zaglavlja sustava.

Naravno, postoji mnogo više proširenja koja su korisna u bilo kojoj drugoj vrsti programiranja koja mogu biti od velike pomoći u kodiranju. Više informacija o ovim proširenjima možete pronaći u dokumentaciji gcc Texinfo.

5.1. Opcije Gcc

gcc prihvaća mnoge opcije naredbi. Srećom, skup opcija kojih stvarno morate biti svjestan nije tako sjajan, a mi ćemo ih pokriti u ovom poglavlju.

Većina opcija su iste ili slične onima ostalih kompajlera, gcc uključuje ogromnu dokumentaciju o svojim opcijama dostupnu putem info gcc (man gcc također daje ove podatke, međutim stranice man se ne ažuriraju tako često kao dokumenti Texinfo).

-o imenu datoteke Određuje ime izlazne datoteke. To obično nije potrebno ako kompilirate u objektnu datoteku, tj. Prema zadanim postavkama, filename.c zamjenjuje se s filename.o. Međutim, ako stvorite izvršnu datoteku, ona će se prema zadanim postavkama (iz povijesnih razloga) kreirati pod imenom a.out. To je također korisno kada želite izlaznu datoteku smjestiti u drugi direktorij.
-iz Kompilira bez povezivanja izvorne datoteke navedene za naredbeni redak. Ovo stvara objektnu datoteku za svaku izvornu datoteku. Kada se koristi make, gcc kompajler se obično poziva za svaku objektnu datoteku; tako je u slučaju pogreške lakše otkriti koju datoteku nije uspjelo prevesti. Međutim, ako ručno upisujete naredbe, često se u jednom gcc pozivu navede više datoteka. Ako se prilikom navođenja više datoteka na naredbenom retku može pojaviti dvosmislenost, 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.
-D foo Definira makronaredbe pretprocesora na naredbenom retku. Možda ćete trebati nadjačati znakove koje ljuska tretira kao posebne. Na primjer, prilikom definiranja niza, izbjegavajte upotrebu razgraničnih znakova ". Dva najčešća načina su" -Dfoo \u003d "bar" "i -Dfoo \u003d \\" bar \\ ". Prvi način djeluje puno bolje ako niz sadrži razmake, jer ljuska se na poseban način odnosi prema prostorima.
-I imenik Dodaje direktorij na popis direktorija za pretraživanje uključenih datoteka.
-L direktorij Dodaje direktorij na popis direktorija koji se pretražuju za biblioteke, gcc će dati prednost dijeljenim knjižnicama u odnosu na statičke, ako nije drugačije naznačeno.
-Jao foo Veze protiv lib foo. Ako nije drugačije naznačeno, gcc preferira povezivanje sa zajedničkim knjižnicama (lib foo .so) u odnosu na statičke (lib foo .a). Povezivač pretražuje sve navedene knjižnice za funkcije u redoslijedu u kojem su navedene. Pretraga završava kad se pronađu sve potrebne funkcije.
-statički Veze samo protiv statičnih knjižnica. Vidi poglavlje 8.
-g, -ggdb Uključuje informacije o otklanjanju pogrešaka. Opcija -g prisiljava gcc da uključuje standardne informacije o otklanjanju pogrešaka. Opcija -ggdb govori vam da uključite ogromnu količinu informacija koje samo gdb program za ispravljanje pogrešaka može razumjeti.
Ako je prostor na disku ograničen ili želite žrtvovati neke funkcije zbog brzine veze, trebali biste upotrijebiti -g. U tom ćete slučaju možda trebati koristiti program za ispravljanje pogrešaka koji nije gdb. Za najpotpunije ispravljanje pogrešaka morate navesti -ggdb. U tom će slučaju gcc pripremiti maksimum detaljne informacije za gdb. Treba napomenuti da, za razliku od većine kompajlera, gcc u optimizirani kôd stavlja neke informacije o otklanjanju pogrešaka. Međutim, praćenje u optimiziranom programu za pronalaženje pogrešaka može biti nezgodno jer tijekom izvođenja može doći do preskakanja i preskakanja fragmenata koda za koje se očekuje da će se izvršiti. Međutim, možete dobiti dobra prezentacija kako optimizacijski kompajleri mijenjaju način izvršavanja koda.
-O, -O n Prisiljava gcc na optimizaciju koda. Prema zadanim postavkama, gcc vrši malu količinu optimizacije; pri specificiranju broja (n), optimizacija se izvodi na određenoj razini. Najčešća razina optimizacije je 2; trenutno je najviša razina optimizacije u gcc standardu 3. Preporučujemo upotrebu -O2 ili -O3; -O3 može povećati veličinu aplikacije, pa ako je to važno, pokušajte oboje. Ako su memorija i prostor na disku važni za vašu aplikaciju, također možete upotrijebiti opciju -Os koja minimizira veličinu koda povećavajući vrijeme izvršavanja. gcc omogućuje ugrađene programe samo kada se primijeni barem minimalna optimizacija (-O).
-ansi Podrška u C programima svih ANSI standarda (X3.159-1989) ili njihovom ISO ekvivalentu (ISO / IEC 9899: 1990) (obično zvanom C89 ili rjeđe C90). Treba napomenuti da ovo nije u potpunosti u skladu s ANSI / ISO standardom.
Opcija -ansi onemogućuje proširenja gcc, koja su obično u suprotnosti s ANSI / ISO standardima. (Zbog činjenice da ova proširenja podržavaju mnogi drugi C kompajleri, to u praksi ne predstavlja problem.) Ovo također definira makronaredbu __STRICT_ANSI__ (kako je opisano kasnije u ovoj knjizi) koju datoteke zaglavlja koriste za podršku okruženju kompatibilnom s ANSI / ISO.
-pedantan Prikazuje sva upozorenja i poruke o pogreškama koje zahtijeva jezični standard ANSI / ISO C. To ne pruža potpunu usklađenost s 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 detaljnosti bit će postavljena za analizator lanaca u odnosu na vaš izvorni kod, gcc vam omogućuje ručno omogućavanje i onemogućavanje svakog upozorenja kompajlera. Sva upozorenja detaljno su navedena u priručniku za gcc.
5.2. Datoteke zaglavlja
5.2.1. dugo dugo

Long long označava da je blok memorije barem toliko velik kao long. Na Intelu i86 i ostalim 32-bitnim platformama long je 32 bita, a long 64 bita. Na 64-bitnim platformama pokazivači i long long su 64 bita, dok long može biti 32 ili 64 bita, ovisno o platformi. Tip long long podržan je u standardu C99 (ISO / IEC 9899: 1999) i dugogodišnje je C proširenje koje pruža gcc.

5.2.2. Ugrađene funkcije

Neki dijelovi zaglavlja Linuxa (posebno oni koji su specifični za određeni sustav) koriste ugrađene funkcije vrlo široko. Brzi su poput makronaredbi (bez troškova funkcijskih poziva) i pružaju sve vrste provjere valjanosti dostupne u uobičajenom pozivu funkcije. Pozivanje koda ugrađenih funkcija mora se kompajlirati s omogućenom barem minimalnom optimizacijom (-O).

5.2.3. Alternativne napredne ključne riječi

U gcc-u svaka proširena ključna riječ (ključne riječi koje nisu obuhvaćene standardom ANSI / ISO) ima dvije verzije: samu ključnu riječ i ključnu riječ okruženu s dvije donje crte s obje strane. Kada se kompajler koristi u standardnom načinu rada (obično kada se koristi opcija -ansi), normalne proširene ključne riječi se ne prepoznaju. Tako, na primjer, ključna riječ atribut u datoteci zaglavlja treba biti napisana kao __attribute__.

5.2.4. Značajke

Ključna riječ s proširenim atributom koristi se za pružanje gcc-u više informacija o funkciji, varijabli ili deklariranom tipu nego što bi to dopuštao ANSI / ISO C kôd. Na primjer, poravnati atribut govori gcc-u kako poravnati varijablu ili tip; atribut upakiran označava da se neće koristiti podmetači; noreturn navodi da se funkcija nikada neće vratiti, što omogućava gcc-u da bolje optimizira i izbjegne lažna upozorenja.

Atributi funkcije deklariraju se dodavanjem u deklaraciju funkcije, na primjer:

poništava die_die_die (int, char *) __attribute__ ((__noreturn__));

Deklaracija atributa postavlja se između zagrada i zareza i sadrži ključnu riječ atributa nakon koje slijede atributi u dvostrukim zagradama. Ako ima mnogo atributa, upotrijebite popis odvojen zarezima.

int printm (char *, ...)

Atribut __ ((const,

format (printf, 1, 2)));

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

O nekim će se atributima raspravljati tijekom nastavka (na primjer, pri opisivanju sklopa zajedničkih knjižnica u poglavlju 8). Sveobuhvatne informacije o atributima mogu se naći u dokumentaciji gcc Texinfo.

S vremena na vrijeme možete se zagledati u Linux zaglavlja. Vjerojatno ćete pronaći niz dizajna koji nisu u skladu s ANSI / ISO. Neke od njih vrijedi razumjeti. Svi konstrukti o kojima se raspravlja u ovoj knjizi detaljno su navedeni u dokumentaciji o gcc-u.

S vremena na vrijeme možete se zagledati u Linux zaglavlja. Vjerojatno ćete pronaći niz dizajna koji nisu u skladu s ANSI / ISO. Neke od njih vrijedi razumjeti. Svi konstrukti o kojima se raspravlja u ovoj knjizi detaljno su navedeni u dokumentaciji o gcc-u.

Sad kad ste naučili par stvari o C standardu, pogledajmo opcije koje nudi gcc-ov kompajler kako biste osigurali usklađenost sa C-standardom u koji upisujete. Tri su načina kako osigurati da je vaš C kôd usklađen sa standardima i bez nedostataka: opcije za kontrolu verzije standarda s kojim se namjeravate pridržavati, definicije za kontrolu datoteka zaglavlja i opcije upozorenja za pokretanje strože provjere koda. ...

Gcc ima ogroman skup mogućnosti, a ovdje ćemo pokriti samo one koje smatramo najvažnijima. Cjelovit popis opcija nalazi se na stranicama gcc internetskog priručnika. Također ćemo ukratko razgovarati o nekim od #define opcija koje možete koristiti; oni bi obično trebali biti navedeni u vašem izvornom kodu prije bilo kojih linija #include ili navedeni u naredbenom retku gcc. Možda ćete biti iznenađeni obiljem mogućnosti za odabir primjenjivog standarda umjesto jednostavne zastavice koja vas prisiljava na korištenje modernog standarda. Razlog je taj što se mnogi stariji programi oslanjaju na ponašanje povijesnog kompajlera i zahtijevat će značajan rad kako bi ih ažurirali na najnovije standarde. Rijetko, ako ikad poželite ažurirati svoj kompajler kako bi mogao početi prekidati pokrenut kôd. Kako se standardi mijenjaju, važno je moći raditi protiv određenog standarda, čak i ako to nije najnovija verzija standarda.

Čak i ako pišete mali program za osobnu upotrebu, kad usklađenost sa standardima možda nije toliko važna, često ima smisla uključiti dodatna upozorenja o gcc-u kako bi prisilio kompajler da traži greške u vašem kodu prije izvođenja programa. To je uvijek učinkovitije od koraka kroz kod u ispravljaču i pitajući se gdje bi mogao biti problem. Kompajler ima mnogo opcija koje nadilaze jednostavnu provjeru standarda, poput mogućnosti otkrivanja koda koji je u skladu sa standardom, ali može imati sumnjivu semantiku. Na primjer, program može imati redoslijed izvršenja koji vam omogućuje pristup varijabli prije nego što je inicijalizirana.

Ako trebate napisati program za zajedničku upotrebu, s obzirom na stupanj usklađenosti sa standardom i vrste upozorenja kompajlera za koje smatrate da su dovoljne, vrlo je važno uložiti malo više truda i postići da se vaš kod sastavi bez ikakvih upozorenja. Ako dopustite neka upozorenja i naviknete se na njihovo ignoriranje, jednog dana može doći do ozbiljnijeg upozorenja koje riskirate da propustite. Ako se vaš kod uvijek kompajlira bez poruka upozorenja, novo upozorenje neizbježno će privući vašu pažnju. Sastavljanje koda bez upozorenja dobra je navika uzeti u obzir.

Opcije sastavljača za standarde praćenja

Ansi je najvažnija opcija standarda i prisiljava sastavljača da djeluje u skladu s jezičnim standardom ISO C90. Onemogućava neka nestandardna gcc proširenja, onemogućava komentare C ++ (//) u C programima i omogućuje obradu ANSI trigrafa (sekvence od tri znaka). Uz to sadrži makronaredbu __ STRICT_ANSI__ koja onemogućava neka proširenja u datotekama zaglavlja koja nisu kompatibilna sa standardom. U sljedećim verzijama prevoditelja, usvojeni standard može se promijeniti.

Std \u003d - Ova opcija pruža finiju kontrolu nad standardom koji se koristi pružanjem parametra koji precizno određuje traženi standard. Slijede glavne mogućnosti:

C89 - podržava standard C89;

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

Gnu89 - Podržava standard C89, ali dopušta neka GNU proširenja i neke funkcije C99. To je zadano u verziji 4.2 gcc-a.

Opcije za praćenje standarda u definiranju direktiva

Postoje konstante (#defines) koje se mogu odrediti opcijama u naredbenom retku ili kao definicije u izvornom kodu programa. Skloni smo pretpostaviti da koriste naredbeni redak prevoditelja.

STRICT_ANSI__ - prisiljava vas da primijenite C ISO standard. Određuje se kada je opcija -ansi navedena u naredbenom retku kompajlera.

POSIX_C_SOURCE \u003d 2 - Omogućuje funkcionalnost definiranu IEEE Std 1003.1 i 1003.2. Na ove ćemo se standarde vratiti nešto kasnije u ovom poglavlju.

BSD_SOURCE - Omogućuje funkcionalnost BSD sustava. Ako su u suprotnosti 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 definicijama POSIX, potonja ima veći prioritet.

Opcije sastavljača za upozorenja

Te se mogućnosti prenose kompajleru iz naredbenog retka. Opet, navodimo samo glavne, cjelovit popis možete pronaći u mrežnom referentnom priručniku za gcc.

Pedant je najmoćnija opcija za provjeru čistoće koda C. Osim što omogućuje provjeru usklađenosti sa standardom C, onemogućava neke tradicionalne C konstrukte koji su zabranjeni standardom, a sva GNU proširenja na standard čine nevaljanima. Ovu bi opciju trebalo koristiti za maksimalizaciju prenosivosti vašeg koda C. Nedostatak je što je prevoditelj jako zabrinut za čistoću vašeg programskog koda, a ponekad morate razbiti glavu kako biste riješili nekoliko preostalih upozorenja.

Wformat - provjerava ispravnost vrsta argumenata funkcija obitelji printf.

Wparentheses - provjerava zagrade, č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 opcije u naredbama prekidača, što se obično smatra dobrim stilom kodiranja.

Zloupotrebljeno - provjerava razne slučajeve, kao što su deklarirane, ali ne i opisane statičke funkcije, neiskorišteni parametri, odbačeni rezultati.

Zid - Uključuje većinu vrsta upozorenja za gcc, uključujući sve prethodne opcije W (koje ne pokriva samo --pedantic). Uz njegovu pomoć lako je postići čistoću programskog koda.

Bilješka

Mnogo je naprednijih opcija upozorenja, detalje potražite na web stranicama gcc. Općenito preporučujemo upotrebu -Wall; to je dobar kompromis između provjere, koja pruža visokokvalitetni programski kod, i prevoditelja koji mora iznijeti puno trivijalnih upozorenja koja je teško svesti na nulu.

OUU je uključen u bilo koju distribuciju Linux i obično se instalira prema zadanim postavkama. GCC sučelje je standardno UNIX sučelje kompajlera, koje datira iz kasnih 60-ih, ranih 70-ih godina prošlog stoljeća - sučelje naredbenog retka. Ne brinite se, tijekom proteklog vremena mehanizam interakcije s korisnikom usavršen je do mogućeg savršenstva u ovom slučaju i radite s GCC-om (ako postoji nekoliko dodatnih uslužnih programa i razumno uređivač teksta) je lakši od bilo kojeg modernog vizualnog IDE-a. Autori kompleta pokušali su što je više moguće automatizirati postupak sastavljanja i sastavljanja aplikacija. Korisnik poziva upravljački program gcc, tumači prosljeđene argumente naredbenog retka (opcije i nazivi datoteka) i za svaku ulaznu datoteku, u skladu s korištenim programskim jezikom, pokreće svoj prevoditelj, a zatim, ako je potrebno, gcc automatski poziva asembler i povezivač (povezivač).

Zanimljivo je da su kompajleri jedna od rijetkih UNIX aplikacija koja brine o ekstenzijama datoteka. Proširenjem, GCC određuje koja se datoteka nalazi ispred nje i što s njom treba (može) učiniti. Izvorne datoteke jezika C mora imati .c proširenje na jeziku C ++po želji .cpp, datoteke zaglavlja na jeziku C .h, .o objektne datoteke itd. Ako upotrebljavate pogrešno proširenje, gcc neće raditi ispravno (ako se uopće slažete, poduzmite nešto).

Krenimo s vježbanjem. Napišimo, kompajliramo i izvršimo neki jednostavni program. Nećemo biti izvorni kao izvorna datoteka primjera programa na jeziku C Stvorimo datoteku sa sljedećim sadržajem:

/ * zdravo.c \u200b\u200b* /

#include

Glavna ( poništiti )
{

Printf ("Pozdrav svijetu \\ n");

povratak 0 ;

Sada, u direktoriju c hello.c, izdajte naredbu:

$ gcc pozdrav.c

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

$ ls
a.iz zdravo.c

Ovo je gotova izvršna datoteka našeg programa. Zadano gcc imenuje izlaznu izvršnu datoteku a.out (nekada je ovo ime značilo izlaz asemblera).

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

Pokrenimo rezultirajuće softver:

$ ./a.out
Pozdrav svijete


Zašto je u naredbi potrebno izričito odrediti put do datoteke da bi se datoteka izvršila iz trenutnog direktorija? Ako put do izvršne datoteke nije izričito naveden, ljuska, interpretirajući naredbe, traži datoteku u direktorijima navedenim u sistemskoj varijabli PATH.

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

Direktoriji na popisu odvojeni su znakom dvotačke. Kada pretražuje datoteke, ljuska gleda direktorije redom kojim su navedene. Prema zadanim postavkama, iz sigurnosnih razloga, trenutni direktorij. nije uključen na popis, pa ljuska neće tražiti izvršne datoteke na njemu.

Zašto se ne preporučuje izrada. u PUTU? Vjeruje se da će u stvarnom višekorisničkom sustavu uvijek postojati neka loša osoba koja će zlonamjerni program smjestiti u javni direktorij s imenom izvršne datoteke koja se podudara s nazivom neke naredbe koju često naziva lokalni administrator s pravima superkorisnika ... Zavjera će uspjeti ako. je na početku popisa direktorija.


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

$ datoteka hello.c
pozdrav.c: Tekst programa ASCII C
$ file annotation.doc
annotation.doc: CDF V2 dokument, Little Endian, Os: Windows, verzija 5.1, kodna stranica: 1251, autor: MIH, predložak: Normal.dot, zadnji put spremio: MIH, revizijski broj: 83, naziv aplikacije za izradu: Microsoft Office Word, ukupno vrijeme uređivanja: 09:37:00, zadnji put tiskano: četvrtak 22. siječnja 07:31:00 2009, vrijeme izrade / datum: ponedjeljak 12. siječnja 07:36:00 2009, posljednje spremljeno vrijeme / datum: četvrtak 22. siječnja 07:34:00 2009, Broj stranica: 1, Broj riječi: 3094, Broj znakova: 17637, Sigurnost: 0

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

Ime izlazne izvršne datoteke (kao i bilo koje druge generirane datoteke gcc) može se mijenjati pomoću opcije -o:

$ gcc -o bok 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 vraćati cijeli broj u ljusku po završetku programa - nula ako je uspješan, i bilo koji drugi način. Protumač ljuske automatski će dodijeliti rezultirajuću vrijednost varijabli okoline pod nazivom? ... Možete pregledati njegov sadržaj pomoću echo $? :

$ ./zdravo
Pozdrav svijete
$ echo $?
0

Iznad toga je rečeno gcc to 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: predobrada, sama kompilacija, sastavljanje, povezivanje (povezivanje).

Opcije gcc omogućuju vam prekid postupka u bilo kojoj od ovih faza.

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

Iskoristivši opcija -E Sljedeći koraci gcc možete prekinuti i pregledati sadržaj datoteke pretprocesora.

$ gcc -E -o bok.i bok.c
$ ls
zdravo.c \u200b\u200bzdravo.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 nepotpisani char __u_char;
typedef nepotpisani kratki int __u_short;
typedef nepotpisan int __u_int;
. . .
extern int printf (__const char * __ ograniči __format, ...);
. . .
# 4 "zdravo.c" 2
glavni (void)
{
printf ("Pozdrav svijetu \\ n");
povratak 0;
}

Nakon obrade u pretprocesoru, izvorni kod našeg programa nabubrio je i dobio nečitljiv oblik. Kôd koji smo svojedobno upisali vlastitim rukama svodio se na nekoliko redaka na samom kraju datoteke. Razlog - uključujući datoteku zaglavlja standardne knjižnice C... Sama datoteka zaglavlja stdio.h sadrži puno različitih stvari i također zahtijeva uključivanje ostalih datoteka zaglavlja.

Obratite pažnju na proširenje datoteke hello.i. Sporazumima gcc .i nastavak odgovara izvornim datotekama jezika C ne zahtijevajući predobradu. Takve se datoteke sastavljaju zaobilazeći pretprocesor:

$ gcc -o bok zdravo.i
$ ls
zdravo zdravo.c \u200b\u200bzdravo.i
$ ./zdravo
Pozdrav svijete

Nakon predobrade, red je na kompilaciji. Prevoditelj pretvara izvorni kod programa visoke razine u kod asemblerskog jezika.

Značenje riječi kompilacija je mutno. Wikipedijanci, na primjer, vjeruju, pozivajući se na međunarodnim standardimata je kompilacija "transformacija izvornog teksta programa napisanog programskim jezikom visoke razine programom kompajlera u jezik blizak stroju ili u objektni kod." U principu, ova nam definicija odgovara, montažni jezik je zaista bliži strojnom jeziku nego C... Ali u svakodnevnom životu pod kompilacijom se najčešće razumijeva jednostavno svaka operacija koja pretvara izvorni kod programa u bilo kojem programskom jeziku u izvršni kôd. Odnosno, postupak koji uključuje sve četiri gore navedene faze također se može nazvati kompilacijom. Slična je dvosmislenost u ovom tekstu. S druge strane, operacija pretvaranja izvornog teksta programa u kod asemblerskog jezika može se označiti i riječju prijevod - "pretvaranje programa predstavljenog u jednom od programskih jezika u program na drugom jeziku i, u određenom smislu, ekvivalentan prvom".

Zaustavljanje procesa stvaranja izvršne datoteke nakon završetka kompilacije omogućuje opcija -S:

$ gcc -S zdravo.c
$ ls
zdravo.c \u200b\u200bzdravo.s
$ datoteka hello.s
hello.s: ASCII program asemblerskog teksta
$ manje zdravo.s
.datoteka "zdravo.c"
.sekcija .rodata
.LC0:
.string "Hello World"
.tekst
.globl glavni
.tip glavni, @funkcija
glavni:
pushl% ebp
movl% esp,% ebp
andl $ -16,% esp
subl. $ 16,% esp
movl $ .LC0, (% esp)
poziv stavlja
movl 0 USD,% eax
napustiti
u mirovini
.size glavna, .- glavna


Datoteka hello.s pojavila se u direktoriju koji sadrži implementaciju programa na montažnom jeziku. Obratite pažnju na to da odredite ime izlazne datoteke s opcije -o u ovom slučaju nije bilo potrebno, gcc automatski ga generirao, zamijenivši ekstenziju .c s .s u izvornom nazivu datoteke. Za većinu osnovnih operacija gcc naziv izlazne datoteke formira se sličnom zamjenom. Ekstenzija .s standardna je za izvorne datoteke asemblerskog jezika.

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

$ gcc -o bok zdravo.s
$ ls
zdravo zdravo.c \u200b\u200bhello.s
$ ./zdravo
Pozdrav svijete

Sljedeća faza postupka montaže je prevođenje koda jezika montaže u strojni kod. Rezultat operacije je objektna datoteka. Objektna datoteka sadrži blokove strojnog koda spremne za izvršenje, blokove podataka, kao i popis funkcija i vanjskih varijabli definiranih u datoteci ( tablica simbola ), ali ne navodi apsolutne adrese funkcije i reference podataka. Datoteka objekta ne može se izravno pokrenuti za izvršenje, ali kasnije (u fazi povezivanja) može se kombinirati s drugim objektnim datotekama (u ovom će se slučaju, u skladu s tablicama simbola, izračunati i popuniti adrese koje postoje između datoteka ukrštenih referenci). Opcija gcc -c, zaustavlja postupak na kraju faze montaže:

$ gcc -c pozdrav.c
$ ls
zdravo.c \u200b\u200bzdravo.o
$ datoteka zdravo.o
hello.o: ELF 64-bitni LSB relocatable, x86-64, verzija 1 (SYSV), nije skinuta

Standardno proširenje za objektne datoteke je .o.

Ako se rezultirajuća objektna datoteka hello.o proslijedi povezivaču, povezivač će izračunati adrese veza, dodati kôd za pokretanje i završetak programa, kôd za pozivanje funkcija knjižnice i kao rezultat ćemo imati gotovu izvršnu datoteku programa.

$ gcc -o zdravo zdravo.o
$ ls
zdravo zdravo.c \u200b\u200bzdravo.o
$ ./zdravo
Pozdrav svijete

Što smo sada učinili (točnije gcc je to učinio za nas) i tu je sadržaj posljednje faze - povezivanje (povezivanje, povezivanje).

Pa, to je oko kompilacije i to je to. Sada se dotaknimo nekih, po mom mišljenju, važnih opcija gcc.

Opcija -I put / do / direktor / s / zaglavlja / datoteke - dodaje navedeni direktorij na popis staza pretraživanja datoteka zaglavlja. Imenik dodan po opciji -I prvo se pretražuje, a zatim se nastavlja u standardnim katalozima sustava. Ako opcije -I više odstupanja koje su naveli skeniraju se s lijeva na desno, kako se pojavljuju opcije.

Opcija -Zid - prikazuje upozorenja uzrokovana potencijalnim pogreškama u kodu koje ne sprečavaju sastavljanje programa, ali to, prema mišljenju prevodioca, može dovesti do određenih problema tijekom njegovog izvršavanja. Važna i korisna opcija, programeri gcc preporučujemo da ga koristite uvijek. Na primjer, puno upozorenja će se izdati prilikom pokušaja sastavljanja datoteke poput ove:

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


$ gcc -o napomena napomena.c
$ gcc -Zid -o primjedba primjedba.c
primjedba.c: 7: upozorenje: vratite zadane vrijednosti tipa na "int"

primjedba.c: 13: upozorenje: izjava bez učinka
primjedba.c: 9: upozorenje: neiskorištena varijabla ‘a’
primjedba.c: 21: upozorenje: kontrola doseže kraj nevažne funkcije
napomena.c: Na najvišoj razini:
napomena.c: 3: upozorenje: 'k' definirano, ali se ne koristi
primjedba.c: 4: upozorenje: 'l' proglašen 'statičnim', ali nikada nije definiran
primjedba.c: U funkciji ‘main’:
primjedba.c: 15: upozorenje: 'c' se koristi neinicijalizirano u ovoj funkciji
napomena.c: 19: upozorenje: 'p' se koristi neinicijalizirano u ovoj funkciji

Opcija -Werror - pretvara sva upozorenja u pogreške. Prekida postupak sastavljanja ako se pojavi upozorenje. Koristi se zajedno sa opcija -Zid.

$ gcc -Pogreška -o primjedba primjedba.c
$ gcc -Werror -Zid -o primjedba primjedba.c
cc1: upozorenja se tretiraju kao pogreške
primjedba.c: 7: pogreška: vraćanje zadanih vrijednosti tipa na "int"
primjedba.c: U funkciji ‘main’:
napomena.c: 13: pogreška: izjava bez učinka
primjedba.c: 9: pogreška: neiskorištena varijabla ‘a’

Opcija -g - postavlja podatke potrebne za program za uklanjanje pogrešaka u objekt ili izvršnu datoteku gdb... Prilikom izrade projekta za naknadno ispravljanje pogrešaka, opcija -g mora biti uključen i u vrijeme sastavljanja i u vrijeme povezivanja.

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

Izvorna datoteka:

/ * krug.c * /

Glavna ( poništiti )
{

int i;

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

povratak i;

Kompilacija sa zadanom razinom optimizacije:

$ gcc -S krug.c
$ manje kruga.s
.datoteka "krug.c"
.tekst
.globl glavni
.tip glavni, @funkcija
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
u mirovini
.size glavna, .- glavna
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stog, "", @ napreduje

Kompilacija s maksimalnom razinom optimizacije:

$ gcc -S -O3 krug.c
$ manje kruga.s
.datoteka "krug.c"
.tekst
.p2align 4.15
.globl glavni
.tip glavni, @funkcija
glavni:
pushl% ebp
movl $ 10,% eax
movl% esp,% ebp
popl% ebp
u mirovini
.size glavna, .- glavna
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stog, "", @ napreduje

U drugom slučaju nema ni nagovještaja petlje u rezultirajućem kodu. Doista, vrijednost i može se izračunati u fazi sastavljanja, što je i učinjeno.

Jao, za stvarne projekte razlika u izvedbi na različitim razinama optimizacije praktički nije primjetna ...

Opcija -O0 - otkazuje bilo kakvu optimizaciju koda. Opcija je obavezna u fazi uklanjanja pogrešaka u aplikaciji. Kao što je gore prikazano, optimizacija može dovesti do promjene u strukturi programa do neprepoznatljivosti, veza između izvršne i izvornog koda neće biti eksplicitna, stoga postupno otklanjanje pogrešaka u programu neće biti moguće. Kad je opcija omogućena -g, preporuča se uključiti i -O0.

Opcija -Os - postavlja optimizaciju ne učinkovitošću koda, već veličinom rezultirajuće datoteke. U ovom slučaju, izvedba programa trebala bi biti usporediva s performansama koda dobivenog tijekom kompilacije sa zadanom razinom optimizacije.

Opcija -march \u003d arhitektura - određuje ciljanu arhitekturu procesora. Popis podržanih arhitektura opsežan je, na primjer, za obitelj procesora Intel / AMD možeš pitati i386, pentium, prescott, opteron sse3 itd Korisnici binarnih distribucija trebaju imati na umu da je poželjno da svi povezani knjižnici budu kompilirani s istom opcijom da bi programi ispravno radili s navedenom opcijom.

Opcije proslijeđene povezivaču bit će razmotrene u nastavku.

Mali dodatak:

Iznad toga je rečeno gcc određuje vrstu (programski jezik) prenesenih datoteka njihovim proširenjem i u skladu s pretpostavljenim tipom (jezikom) vrši radnje na njima. Korisnik je dužan nadzirati proširenja stvorenih datoteka, odabirući ih prema ugovoru gcc... U stvarnosti gcc možete klizati datoteke s proizvoljnim imenima. Opcija Gcc -x omogućuje vam izričito određivanje programskog jezika sastavljenih datoteka. Ova se opcija odnosi na sve naredne datoteke navedene u naredbi (dok se ne pojavi sljedeća opcija -x). Mogući argumenti opcije:

c-zaglavlje c-cpp-izlaz

c ++ c ++ - zaglavlje c ++ - cpp-output

cilj-c objektiv-c zaglavlje Cilj-c-cpp-izlaz

cilj-C ++ Cilj-C ++ - zaglavlje Cilj-C ++ - cpp-izlaz

asembler asembler-sa-cpp-om

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 s izvornim kodom koju je predprocesor obrađivao). Provjerimo:

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

Odvojena kompilacija

Snaga jezika C / C ++ je mogućnost podjele izvornog koda programa na nekoliko datoteka. Još se više može reći - mogućnost zasebne kompilacije osnova je jezika, bez njegove učinkovite upotrebe C nije zamislivo. Programiranje s više datoteka omogućuje vam implementaciju na C veliki projekti poput Linux (ovdje ispod riječi Linux znači i jezgru i sustav u cjelini). Što odvojena kompilacija daje programeru?

1. Omogućuje vam da kôd programa (projekta) učinite čitljivijim. Izvorna datoteka za nekoliko desetaka zaslona postaje gotovo nepotpuna. Ako ga, u skladu s nekom (unaprijed smišljenom) logikom, rastavite na niz malih fragmenata (svaki u zasebnoj datoteci), bit će puno lakše nositi se sa složenošću projekta.

2. Omogućuje smanjenje vremena za ponovno sastavljanje projekta. Ako se u jednoj datoteci izvrše izmjene, nema smisla ponovno sastaviti cijeli projekt, dovoljno je ponovno sastaviti samo ovu promijenjenu datoteku.

3. Omogućuje vam distribuciju rada na projektu među više programera. Svaki programer stvara i otklanja pogreške u svom dijelu projekta, ali u bilo kojem trenutku bit će moguće prikupiti (obnoviti) sve rezultirajuće razvoje u konačni proizvod.

4. Bez zasebne kompilacije ne bi bilo knjižnica. Ponovna upotreba i distribucija koda na C / C ++, a kod je binarni, što omogućuje, s jedne strane, programerima pružiti jednostavan mehanizam za njegovo uključivanje u svoje programe, s druge strane, da od njih sakriju određene detalje implementacije. Kad radite na projektu, vrijedi li uvijek razmišljati i ne trebati nešto od onoga što je već učinjeno negdje u budućnosti? Možda biste trebali unaprijed odabrati i dizajnirati 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 uvjetovanog).

Skup datoteka izvornog koda:

/ * main.c * /

#include

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

int glavni ( poništiti )
{

Prvo ();
drugi ();

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

povratak 0 ;


/ * prvo.h * /

poništiti prvo ( poništiti );


/ * prvo.c * /

#include

#include "first.h"

poništiti prvo ( poništiti )
{

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


/ * drugi.h * /

poništiti drugo ( poništiti );


/ * drugi.c * /

#include

#include "second.h"

poništiti drugo ( poništiti )
{

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

Općenito imamo ovo:

$ ls
prvo.c prvo.h glavno.c drugo.c drugo.h

Sva se ta ekonomija može objediniti u jednu naredbu:

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

Samo nam to neće pružiti praktički nikakve bonuse, dobro, osim iznimno strukturiranog i čitljivog koda, raspoređenog u nekoliko datoteka. Sve gore navedene prednosti pojavit će se u slučaju ovog pristupa kompilaciji:

$ gcc -Wall -c main.c
$ gcc -Wall -c prvo.c
$ gcc -Zidni -c drugi.c
$ ls
prvo.c prvo.h prvo.o glavno.c glavno.o drugo.c drugo.h drugo.o
$ gcc -o glavni glavni.o prvi.o drugi.o
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Što smo učinili? Iz svake izvorne datoteke (sastavljanje s opcijom c) je dobio datoteku objekta. Objektne datoteke tada su povezane u konačnu izvršnu datoteku. Naravno ekipe gcc je postalo više, ali nitko ručno ne prikuplja projekte, za to postoje komunalni alati (najpopularniji napraviti). Sve gore navedene prednosti zasebne kompilacije očitovat će se korištenjem uslužnih programa za prikupljanje.

Postavlja se pitanje: kako povezivač uspijeva sastaviti objektne datoteke pravilno izračunavajući adresiranje poziva? Kako on uopće zna da datoteka second.o sadrži kôd druge () funkcije, a kôd datoteke main.o sadrži njen poziv? Ispada da je sve jednostavno - objektna datoteka sadrži tzv tablica simbola , uključujući imena nekih kodnih pozicija (funkcije i vanjske varijable). Veznik skenira tablicu simbola svake objektne datoteke, traži uobičajene (s odgovarajućim imenima) položaje, na temelju kojih donosi zaključke o stvarnom mjestu koda korištenih funkcija (ili blokova podataka) i, u skladu s tim, ponovno izračunava adrese poziva u izvršnoj datoteci.

Tablicu simbola možete pregledati pomoću uslužnog programa nm.

$ nm glavno.o
ti prvi
00000000 T glavni
U stavlja
U drugo
$ nm prvo.o
00000000 T prvo
U stavlja
$ nm sekunde.o
U stavlja
00000000 T sekunde

Pojava poziva puta objašnjava se upotrebom standardne funkcije knjižnice printf () koja se pretvorila u put () u vrijeme kompajliranja.

Tablica simbola napisana je ne samo u objektnoj datoteci, već i u izvršnoj datoteci:

$ nm glavni
08049f20 d _DINAMIČKI
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484fc R _IO_stdin_used
w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0c d __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048538 r __FRAME_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
080484b0 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
0804a010 D __dso_handle
w __gmon_start__
080484aa T __i686.get_pc_thunk.bx
08049f0c d __init_array_end
08049f0c d __init_array_start
08048440 T __libc_csu_fini
08048450 T __libc_csu_init
U [e-pošta zaštićena]@ GLIBC_2.0
0804a014 A _edata
0804a01c A _završetak
080484dc T _fini
080484f8 R _fp_hw
080482b8 T _init
08048330 T _pokretanje
0804a014 b završeno. 7021
0804a00c W data_start
0804a018 b dtor_idx.7023
0804840c T prvo
080483c0 t frame_dummy
080483e4 T glavni
U [e-pošta zaštićena]@ GLIBC_2.0
08048420 T sekunde

Uključivanje tablice simbola u izvršnu datoteku posebno je potrebno kako bi se olakšalo ispravljanje pogrešaka. U principu, zapravo nije potrebno za pokretanje aplikacije. Za izvršne datoteke stvarnih programa, s mnogim definicijama funkcija i vanjskim varijablama, koristeći hrpu različitih knjižnica, tablica simbola postaje prilično opsežna. Da biste smanjili veličinu izlazne datoteke, ona se može ukloniti pomoću s opcijom gcc -s.

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

Treba imati na umu da tijekom povezivanja povezivač ne vrši provjere u kontekstu poziva funkcije, ne nadgleda ni vrstu povratne vrijednosti, ni vrstu i broj prihvaćenih parametara (i nema mjesta za dobivanje takvih podataka). Sva provjera valjanosti poziva mora se obaviti u vrijeme sastavljanja. U slučaju programiranja s više datoteka, to zahtijeva upotrebu mehanizma datoteke zaglavlja jezika C.

knjižnice

Knjižnica - na jeziku C, datoteka koja sadrži objektni kôd koji se tijekom povezivanja može povezati s programom pomoću biblioteke. Zapravo, knjižnica je zbirka objektnih datoteka povezanih na poseban način.

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

S gledišta operativnog sustava i aplikacijskog softvera, knjižnice jesu statički i podijeljen (dinamičan ).

Kôd statičke knjižnice uključen je u izvršnu datoteku tijekom povezivanja potonje. Ispada da je knjižnica "hardwired" u datoteku, a knjižnica je "spojena" s ostatkom koda datoteke. Program koji koristi statičke biblioteke postaje samostalan i može se pokrenuti na gotovo bilo kojem računalu s odgovarajućom arhitekturom i operativnim sustavom.

Kôd zajedničke knjižnice učitava i povezuje s programskim kodom operativni sustav, na zahtjev programa tijekom njegovog izvršavanja. Kôd dinamičke knjižnice nije uključen u izvršnu datoteku programa, već je samo veza do biblioteke uključena u izvršnu datoteku. Kao rezultat toga, program koji koristi zajedničke knjižnice prestaje biti samostalan i može se uspješno pokretati samo na sustavu u kojem su instalirane uključene knjižnice.

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

1. Veličina izvršne datoteke uvelike se smanjuje. U sustavu koji uključuje mnogo binarnih datoteka koje koriste isti kôd, nije potrebno čuvati kopiju tog koda za svaku izvršnu datoteku.

2. Šifra zajedničke knjižnice koju koristi nekoliko aplikacija pohranjuje se u RAM-u u jednoj kopiji (zapravo, nije sve tako jednostavno ...), što rezultira smanjenjem potrebe sustava za dostupnom RAM-om.

3. Nema potrebe za obnovom svake izvršne datoteke u slučaju promjena u kodu zajedničke knjižnice za njih. Promjene i ispravci koda dinamičke knjižnice automatski će se odraziti u svakom programu koji ga koristi.

Bez paradigme zajedničke knjižnice ne bi bilo prethodno sastavljenih (binarnih) distribucija Linux (da, bez obzira na to što nije postojalo). Zamislite veličinu distribucije, čija bi svaka binarna datoteka sadržavala kod standardne knjižnice C (i sve ostale uključene knjižnice). Zamislite samo što bi trebalo učiniti kako bi se sustav ažurirao nakon ispravljanja kritične ranjivosti u jednoj od široko korištenih knjižnica ...

Sad malo prakse.

Za ilustraciju koristimo skup izvornih datoteka iz prethodnog primjera. Kôd (implementacija) prve () i druge () funkcije stavit ćemo u našu domaću knjižnicu.

U Linuxu je usvojena sljedeća shema imenovanja datoteka knjižnice (iako se ona ne poštuje uvijek) - naziv datoteke knjižnice započinje s prefiksom lib, nakon čega slijedi sam naziv knjižnice, na kraju produžetka .a ( arhiva ) - za statičku biblioteku, .so ( zajednički objekt ) - za dijeljeno (dinamično) nakon proširenja brojevi inačica navode se kroz točku (samo za dinamičke biblioteke). Ime koje odgovara knjižnici datoteka zaglavlja (opet obično) sastoji se od naziva knjižnice (bez prefiksa i verzije) i .h nastavka. Na primjer: libogg.a, libogg.so.0.7.0, ogg.h.

Prvo, kreirajmo i koristimo statičku knjižnicu.

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

/ * zdravo h * /

poništiti prvo ( poništiti );
poništiti drugo ( poništiti );

Naravno, linije:

#include "first.h"


#include "second.h"

u datotekama main.c, first.c i second.c potrebno je zamijeniti sa:

#include "hello.h"

Unesite sada sljedeći niz naredbi:

$ gcc -Wall -c prvo.c
$ gcc -Zidni -c drugi.c
$ ar crs libhello.a prvi.o drugi.o
$ file libhello.a
libhello.a: trenutna arhiva ar

Kao što je već spomenuto, knjižnica je zbirka objektnih datoteka. S prve dvije naredbe stvorili smo ove objektne datoteke.

Dalje, objektne datoteke morate povezati u skup. Za to se koristi arhiver ar - uslužni program "lijepi" nekoliko datoteka u jednu, rezultirajuća arhiva uključuje informacije potrebne za vraćanje (izdvajanje) svake pojedine datoteke (uključujući atribute vlasništva, pristupa, vremena). Ne vrši se nikakva "kompresija" sadržaja arhive ili druga transformacija pohranjenih podataka.

Opcija C arname - stvoriti arhivu, ako arhiva s imenom arname ne postoji, stvorit će se, inače će se datoteke dodati u postojeću arhivu.

Opcija r - postavlja način ažuriranja arhive, ako datoteka s navedenim imenom već postoji u arhivi, ona će se izbrisati, a nova će datoteka biti dodana na kraj arhive.

Opcija s - dodaje (ažurira) indeks arhive. U ovom je slučaju arhivski indeks tablica u kojoj je za svako simbolično ime (ime funkcije ili blok podataka) definirano u arhiviranim datotekama povezano odgovarajuće ime datoteke datoteke. Arhivski indeks potreban je za ubrzavanje rada s knjižnicom - da biste pronašli potrebnu definiciju, nije potrebno pregledavati tablice simbola svih arhivskih datoteka, možete izravno otići do datoteke koja sadrži željeno ime. Indeks arhive možete pregledati pomoću već poznatog uslužnog programa nm koristeći ga s opcijom -s (bit će prikazane i tablice simbola svih objektnih datoteka arhive):

$ nm -s libhello.a
Kazalo arhive:
prvo u prvom.o
drugo u drugo.o

first.o:
00000000 T prvo
U stavlja

second.o:
U stavlja
00000000 T sekunde

Postoji poseban uslužni program za stvaranje indeksa arhive ranlib... Knjižnica libhello.a mogla je biti kreirana ovako:

$ ar cr libhello.a prvo.o drugo.o
$ ranlib libhello.a

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

Sada iskoristimo našu biblioteku:

$ gcc -Wall -c main.c
$
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Djela...

E sad komentari ... Postoje dvije nove mogućnosti gcc:

Opcija -l name - proslijeđeno povezivaču, ukazuje na potrebu povezivanja biblioteke libname s izvršnom datotekom. Povezati znači označiti da su takve i takve funkcije (vanjske varijable) definirane u takvoj i takvoj knjižnici. U našem primjeru knjižnica je statična, svi simbolični nazivi odnosit će se na kôd smješten izravno u izvršnoj datoteci. Obratite pažnju na mogućnosti -l naziv knjižnice naveden je kao ime bez prefiksa lib.

Opcija -L / put / do / direktorija / sa / bibliotekama - proslijeđeno povezivaču, određuje put do direktorija koji sadrži povezane knjižnice. U našem slučaju, poanta . , veznik će prvo potražiti knjižnice u trenutnom direktoriju, a zatim u direktorijima definiranim u sustavu.

Ovdje treba dati mali komentar. Činjenica je da za brojne mogućnosti gcc važan je redoslijed kojim se pojavljuju na naredbenom retku. Na taj način povezivač traži kod koji se podudara s imenima navedenim u tablici simbola datoteke u knjižnicama navedenim u naredbenom retku. nakon naziv ove datoteke. Linker ignorira sadržaj knjižnica navedenih prije naziva datoteke:

$ gcc -Wall -c main.c
$ gcc -o glavni -L. -zdravo glavno.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. -lhello
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Takva značajka ponašanja gcc zbog želje programera da korisniku omoguće mogućnost kombiniranja datoteka s knjižnicama na različite načine, korištenja isprekidanih imena ... Po mom mišljenju, ako je moguće, bolje je ne gnjaviti se s tim. Općenito, povezane knjižnice moraju biti navedene nakon naziva datoteke koja se odnosi na njih.

Postoji alternativni način za određivanje mjesta knjižnica u sustavu. Ovisno o distribuciji, varijabla okoline LD_LIBRARY_PATH ili LIBRARY_PATH može pohraniti popis direktorija odvojen dvotočkom i u kojem veznik treba potražiti knjižnice. U pravilu, ova varijabla po defaultu uopće nije definirana, ali ništa ne sprječava njezinu izradu:

$ 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 izvršenje je izašlo s povratnim kodom 1
$ izvoz LIBRARY_PATH \u003d.
$ gcc -o glavni glavni.o -zdravo
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Manipulacije s varijablama okoline korisne su pri stvaranju i uklanjanju pogrešaka s vlastitim knjižnicama, kao i ako je potrebno povezati neke nestandardne (zastarjele, ažurirane, izmijenjene - općenito različite od one uključene u distribuciju) zajedničku knjižnicu s aplikacijom.

Sada napravimo i koristimo dinamičnu knjižnicu.

Skup izvornih datoteka ostaje nepromijenjen. Ulazimo u naredbe, pogledajte što se dogodilo, pročitajte komentare:

$ gcc -Zid -fPIC -c prvo.c
$ gcc -Zidni -fPIC -c drugi.c
$ gcc -shared -o libhello.so.2.4.0.5 -Wl, -soname, libhello.so.2 first.o second.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 skinut

Datoteka libhello.so.2.4.0.5 naša je zajednička knjižnica. O tome kako ga koristiti razgovarat ćemo u nastavku.

Sad komentari:

Opcija -fPIC - zahtijeva da kompajler prilikom stvaranja objektnih datoteka generira kod neovisan o položaju (PIC - pozicija neovisnog koda ), njegova glavna razlika je u načinu predstavljanja adresa. Umjesto određivanja fiksnih (statičkih) pozicija, sve se adrese izračunavaju na temelju odstupanja navedenih u globalna offset tablica (globalna offset tablica - DOBILO ). Format koda neovisan o položaju omogućuje izvršnim modulima povezivanje s glavnim programskim kodom u trenutku učitavanja. Sukladno tome, glavna svrha koda neovisnog o položaju je stvaranje dinamičkih (zajedničkih) knjižnica.

Opcija -shared - ukazuje gccda rezultat ne bi trebao biti izvršna datoteka, već zajednički objekt - dinamična knjižnica.

Opcija -Wl, -soname, libhello.so.2 - setovi soname knjižnice. O sonameu ćemo detaljno govoriti u sljedećem odlomku. Sada razgovarajmo o formatu opcije. Na prvi pogled naoko čudno, konstrukcija sa zarezima namijenjena je izravnoj interakciji korisnika s povezivačem. Tijekom sastavljanja gcc poziva povezivač automatski, automatski, prema vlastitom nahođenju, gcc donosi opcije potrebne za uspješan završetak posla. Ako korisnik treba sam intervenirati u procesu povezivanja, može koristiti posebnu opciju gcc -Wl, -option, value1, value2 ...... Što znači prijenos na povezivač ( -Wl) opcija -opcija s argumentima vrijednost1, vrijednost2 itd U našem slučaju, opcija je proslijeđena povezivaču -soname s argumentom libhello.so.2.

Sad o sonameu. Prilikom stvaranja i distribucije knjižnica postoji problem kompatibilnosti i kontrole verzija. Da bi sustav, posebno dinamički učitavač knjižnice, imao ideju koja je verzija knjižnice korištena prilikom sastavljanja aplikacije i, u skladu s tim, nužna za njezino uspješno funkcioniranje, osiguran je poseban identifikator - soname , smješten i u datoteku same knjižnice i u izvršnu datoteku aplikacije. Identifikator soname je niz koji uključuje naziv knjižnice s prefiksom lib, dot, dakle ekstenzija, opet točka i jedna ili dvije (odvojene točkama) znamenke verzije knjižnice - lib name .so. x. y. Odnosno, ime se podudara sa nazivom datoteke biblioteke do prve ili druge znamenke broja verzije. Neka ime izvršne datoteke naše knjižnice bude libhello.so.2.4.0.5, tada ime knjižnice može biti libhello.so.2. Pri promjeni sučelja knjižnice mora se promijeniti njezino ime! Svaka izmjena koda koja rezultira nekompatibilnošću s prethodnim izdanjima mora biti popraćena novim imenom.

Kako to sve funkcionira? Pretpostavimo da je za uspješno izvršavanje neke aplikacije potrebna biblioteka pod nazivom hello, neka je sustav ima, s imenom bibliotečke datoteke libhello.so.2.4.0.5, i imenom softvera libhello.so.2 knjižnice. U fazi kompilacije aplikacije, povezivač, prema opciji -Zdravo, tražit će u sustavu datoteku pod nazivom libhello.so. U stvarnom sustavu libhello.so simbolična je poveznica s libhello.so.2.4.0.5. Dobivši pristup datoteci knjižnice, povezivač će pročitati u njemu zapisanu vrijednost soname i, između ostalog, smjestiti će je u izvršnu datoteku aplikacije. Kada se aplikacija pokrene, dinamički učitavač knjižnice primit će zahtjev za povezivanje knjižnice s pročitanim sonameom iz izvršne datoteke i pokušat će pronaći knjižnicu u sustavu čiji naziv datoteke odgovara sonameu. Odnosno, utovarivač će pokušati pronaći datoteku libhello.so.2. Ako je sustav ispravno konfiguriran, treba sadržavati simboličku vezu libhello.so.2 s datotekom libhello.so.2.4.0.5, uređaj za učitavanje će pristupiti potrebnoj biblioteci i potom će ga bez oklijevanja (i bez provjere bilo čega drugog) povezati s aplikacijom. Sad zamislite da smo tako kompajliranu aplikaciju migrirali u drugi sustav, gdje je raspoređena samo prethodna verzija knjižnice sa imenom pod imenom libhello.so.1. Pokušaj pokretanja programa rezultirat će pogreškom jer na ovom sustavu ne postoji datoteka s imenom libhello.so.2.

Dakle, u fazi kompilacije veznik mora osigurati bibliotečku datoteku (ili simboličku vezu do bibliotečke datoteke) pod nazivom lib name. Dakle, u vrijeme izvršavanja učitavač treba datoteku (ili simboličku vezu) nazvanu ime lib .so. x. y. Kako se zove lib .so. x. y mora odgovarati soname nizu korištene knjižnice.

U binarnim distribucijama, datoteka biblioteke libhello.so.2.4.0.5 i veza na nju libhello.so.2 bit će u pravilu smještene u paket libhello, a veza libhello.so, potrebna samo za kompilaciju, zajedno sa zaglavnom datotekom biblioteke hello.h pakirano u paket libhello-devel (paket devel sadržavat će i datoteku statičke verzije biblioteke libhello.a, statička biblioteka se može koristiti, također samo u fazi kompilacije). Kod raspakiranja paketa sve navedene datoteke i poveznice (osim hello.h) nalazit će se u jednoj mapi.

Provjerimo da je navedeni redoslijed imena ustvari upisan u našu bibliotečku datoteku. Iskoristimo mega uslužni program objdump s opcijom -p :

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


Korisnost objdump - moćan alat koji vam omogućuje da dobijete sveobuhvatne informacije o unutarnjem sadržaju (i uređaju) objekta ili izvršne datoteke. Na korisničkoj stranici to stoji objdump prije svega, bit će korisno programerima koji stvaraju alate za uklanjanje pogrešaka i kompilaciju, a ne samo pisanje bilo kakvih aplikacijskih programa :) Osobito s opcijom -D to je rastavljač. Iskoristili smo opciju -p - prikazati razne meta informacije o objektnoj datoteci.

U ovom primjeru stvaranja knjižnice neumorno smo slijedili načela zasebne kompilacije. Dakako, knjižnica bi se mogla sastaviti ovako, uz jedan poziv gcc:

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

Pokušajmo sada koristiti rezultirajuću biblioteku:

$ gcc -Wall -c main.c
$
/ usr / bin / ld: ne mogu pronaći -lhello
collection2: ld vratio 1 status izlaska

Linker psuje. Sjetite se gore rečenog o simboličkim vezama. Izradite libhello.so i pokušajte ponovo:

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

Sad su svi sretni. Pokrećemo kreiranu binarnu datoteku:

Pogreška ... Utovarivač psuje, ne može pronaći knjižnicu libhello.so.2. Provjerimo je li veza do libhello.so.2 stvarno registrirana u izvršnoj datoteci:

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

$ ln -s libhello.so.2.4.0.5 libhello.so.2
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Uspjelo je ... Sada komentariše nove opcije gcc.

Opcija -Wl, -rpath,. - već poznata konstrukcija, proslijedite opciju linkeru -rpath s argumentom . ... Kroz -rpath u izvršnu datoteku programa možete napisati dodatne staze po kojima će zajednički učitavač knjižnice tražiti datoteke knjižnice. U našem slučaju staza je registrirana . - pretraživanje datoteka iz biblioteke započet će iz trenutnog direktorija.

$ objdump -p glavni | grep RPATH
RPATH.

Zahvaljujući ovoj opciji, prilikom pokretanja programa nema potrebe za promjenom varijabli okruženja. Jasno je da ako premjestite program u drugi direktorij i pokušate ga pokrenuti, datoteka knjižnice neće biti pronađena, a loader će dati poruku o pogrešci:

$ mv glavni ..
$ ../main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Pomoću uslužnog programa možete saznati i koje su zajedničke knjižnice aplikaciji potrebne lDD:

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

U izlazu lDD za svaku potrebnu knjižnicu navode se njezino ime i puni put do datoteke knjižnice, određeni u skladu s postavkama sustava.

Sada je vrijeme za razgovor o tome gdje sustav treba smjestiti bibliotečke datoteke, gdje ih program za učitavanje pokušava pronaći i kako upravljati tim postupkom.

Prema dogovorima FHS (Standard hijerarhije datoteka) sustav mora imati dva (barem) direktorija za spremanje datoteka knjižnice:

/ lib - ovdje se prikupljaju glavne distribucijske knjižnice potrebne za rad programa iz / bin i / sbin;

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

Datoteke zaglavlja koje odgovaraju knjižnicama trebaju se nalaziti u direktoriju / usr / include.

Učitavač će prema zadanim postavkama tražiti datoteke knjižnice u tim direktorijima.

Osim gore navedenih, sustav mora sadržavati i / usr / local / lib direktorij - moraju postojati knjižnice koje korisnik korisnik samostalno razmješta, zaobilazeći sustav upravljanja paketom (nije uključen u distribucijski komplet). Primjerice, knjižnice prevedene iz izvora bit će zadane u ovom direktoriju (programi instalirani iz izvora bit će smješteni u / usr / local / bin i / usr / local / sbin, naravno da govorimo o binarnim distribucijama). Zaglavlja knjižnice u ovom će slučaju biti smještena u / usr / local / include.

U brojnim distribucijama (u Ubuntu) Učitavanje nije konfigurirano za pregled direktorija / usr / local / lib, stoga, ako korisnik instalira biblioteku iz izvora, sustav je neće vidjeti. To rade autori distribucijskog kompleta posebno kako bi naučili korisnika da instalira softver samo putem sustava upravljanja paketima. Kako postupiti u ovom slučaju bit će opisano u nastavku.

Zapravo, kako bi pojednostavio i ubrzao proces pronalaženja bibliotečkih datoteka, program za učitavanje ne gleda gornje direktorijume svaki put kada mu se pristupa, već koristi bazu podataka pohranjenu u /etc/ld.so.cache datoteci (knjižnična predmemorija). Sadrži informacije o tome gdje se u sustavu nalazi datoteka knjižnice koja odgovara danom imenu. Učitavač, nakon što je primio popis knjižnica potrebnih za određenu aplikaciju (popis knjižnica soname naveden u izvršnoj datoteci programa), koristi /etc/ld.so.cache kako bi odredio put do datoteke svake potrebne knjižnice i učitao je u memoriju. Uz to, loader može pregledati direktorije navedene u sistemskim varijablama LD_LIBRARY_PATH, LIBRARY_PATH i u polju RPATH izvršne datoteke (vidi gore).

Za upravljanje i ažuriranje predmemorije knjižnice koristite uslužni program ldconfig... Ako trčite ldconfig bez ikakvih opcija, program će skenirati direktorije navedene u naredbenom retku, pouzdane direktorije / lib i / usr / lib, direktorije navedene u datoteci /etc/ld.so.conf. Za svaku datoteku knjižnice u navedenim direktorijima, soname će se čitati, stvorit će se simbolična veza temeljena na sonameu, ažurirat će se podaci u /etc/ld.so.cache.

Provjerimo gore navedeno:

$ ls
pozdrav.h libhello.tako libhello.so.2.4.0.5 glavni.c
$
$ sudo ldconfig / full / path / to / kataogu / c / example
$ ls
pozdrav.h libhello.so libhello.so.2 libhello.so.2.4.0.5 main main.c
$ ./main
Prva funkcija ...
Druga funkcija ...
Glavna funkcija ...

Prvi poziv ldconfig dodali smo našu knjižnicu u predmemoriju, isključili je drugim pozivom. Imajte na umu da je prilikom sastavljanja main opcije izostavljena -Wl, -rpath,., kao rezultat toga, loader je tražio potrebne knjižnice samo u predmemoriji.

Sada bi trebalo biti jasno što učiniti ako je nakon instaliranja knjižnice iz izvora sustav ne vidi. Prije svega, u datoteku /etc/ld.so.conf morate unijeti puni put do direktorija s datotekama knjižnice (prema zadanim postavkama / usr / local / lib). Format /etc/ld.so.conf - datoteka sadrži popis direktorija, odvojene dvotočkom, razmakom, karticom ili novim redom u kojima možete pretraživati \u200b\u200bknjižnice. Onda nazovite ldconfig bez ikakvih opcija, ali s nadljudskim pravima. Sve bi trebalo raditi.

Pa, na kraju, razgovarajmo o tome kako koegzistiraju statičke i dinamičke verzije knjižnica. Koje je stvarno pitanje? Iznad, kada se raspravljalo o prihvaćenim imenima i lokacijama datoteka knjižnice, rečeno je da su datoteke statičke i dinamičke verzije knjižnice pohranjene u istom direktoriju. Kako gcc će znati koju vrstu knjižnice želimo koristiti? Dinamička biblioteka je zadano preferirana. Ako povezivač pronađe dinamičnu datoteku knjižnice, ne ustručava se povezati je s izvršnom datotekom programa:

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

Obratite pažnju na veličinu izvršne datoteke programa. To je najmanji mogući. Sve korištene knjižnice dinamički su povezane.

postojati gcc -statička opcija - upućivanje povezivača da koristi samo statičke verzije svih knjižnica potrebnih za aplikaciju:

$ gcc -static -o glavni glavni.o -L. -lhello
$ datoteka glavna
glavno: ELF 64-bitni LSB izvedljiv, x86-64, verzija 1 (GNU / Linux), statički povezan, za GNU / Linux 2.6.15, nije oduzet
$ 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 - u datoteku su uključene knjižnice standardnih jezika C... Sada se naša aplikacija može sigurno prenijeti iz direktorija u direktorij, pa čak i na druge strojeve, kod biblioteke hello nalazi se unutar datoteke, program je potpuno autonoman.

Što ako trebate statički povezati samo dio korištenih knjižnica? Moguća varijanta rješenja - ime statične verzije knjižnice razlikuje od naziva zajedničke, a prilikom sastavljanja aplikacije navedite koju verziju želimo koristiti ovaj put:

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

Budući da je veličina koda biblioteke libhello zanemariva,

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

veličina rezultirajuće izvršne datoteke praktički se ne razlikuje od veličine datoteke stvorene pomoću dinamičkog povezivanja.

Pa, to je vjerojatno sve. Veliko hvala svima koji su u ovom trenutku završili čitanje.

Uvriježeno je mišljenje da GCC zaostaje za ostalim sastavljačima u pogledu izvedbe. U ovom ćemo članku pokušati shvatiti koje bi osnovne optimizacije kompajlera GCC trebale primijeniti da bi se postigle prihvatljive performanse.

Koje su zadane opcije u OUU?

(1) Prema zadanim postavkama, GCC koristi razinu optimizacije "-O0". Očito nije optimalno za izvedbu i ne preporučuje se za sastavljanje konačnog proizvoda.
GCC ne prepoznaje arhitekturu na kojoj započinje kompilacija dok se ne proslijedi opcija "-march \u003d native". Prema zadanim postavkama, GCC koristi opciju navedenu tijekom njegove konfiguracije. Da biste saznali GCC konfiguraciju, samo pokrenite:

To znači da će GCC vašim opcijama dodati “-march \u003d corei7” (osim ako nije navedena druga arhitektura).
Većina GCC-ovih kompajlera za x86 (baza za 64-bitni Linux) dodan je: "-mtune \u003d generički -march \u003d x86-64" datim opcijama, jer u konfiguraciji nisu navedene opcije arhitekture. Uvijek možete saznati sve opcije donesene prilikom pokretanja GCC-a, kao i njegove interne opcije, pomoću naredbe:

Kao rezultat, često korišteni:

Korištena arhitektura važna je za izvedbu. Jedina iznimka mogu se smatrati oni programi u kojima pozivanje funkcija knjižnice traje gotovo čitavo vrijeme pokretanja. GLIBC može odabrati optimalnu funkciju za određenu arhitekturu u vrijeme izvođenja. Važno je napomenuti da kad su statički povezane, neke GLIBC funkcije nisu verzirane 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čnom zarezom jer su konfigurirani bez "-mfpmath \u003d sse". Samo ako GCC konfiguracija sadrži "--with-mfpmath \u003d sse":

kompajler će prema zadanim postavkama koristiti SSE model. U svim ostalim slučajevima bolje je dodati opciju "-mfpmath \u003d sse" u izgradnju u 32-bitnom načinu.
Dakle, često se koristi:

Dodavanje opcije "-mfpmath \u003d sse" važno je u 32-bitnom načinu! Iznimka je prevoditelj koji u svojoj konfiguraciji ima "--with-mfpmath \u003d sse".

32-bitni način rada ili 64-bitni?

32-bitni način rada obično se koristi za smanjenje količine korištene memorije i, kao posljedicu, ubrzavanje rada s njom (više podataka se stavlja u predmemoriju).
U 64-bitnom načinu rada (u usporedbi s 32-bitnim načinom rada) broj dostupnih javnih registara povećava se sa 6 na 14, XMM registri s 8 na 16. Također, sve 64-bitne arhitekture podržavaju proširenje SSE2, tako da u 64-bitnom načinu ne morate dodavati opciju "-mfpmath" \u003d sse ”.
Za brojanje zadataka preporučuje se korištenje 64-bitnog načina, a za mobilne aplikacije 32-bitnog načina.

Kako postižete najbolje performanse?

Ne postoji određeni skup opcija za maksimalne performanse, ali GCC ima mnogo opcija koje treba isprobati. Ispod je tablica s preporučenim opcijama i predviđanjima 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 problema sastavljenih s GCC verzijom 4.7. Također se pretpostavlja da je konfiguracija kompajlera rađena za generički x86-64.
Prognoza povećanja izvedbe 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 izvedbe računskih zadataka u odnosu na “-O2” (u 64-bitnom načinu):
-m64 -brzo -flto ~17%
-m64 -brzo -flto -march \u003d izvorno ~21%
-m64 -Obrz -flto -march \u003d native -funroll-petlje ~22%

Prednost 64-bitnog načina u odnosu na 32-bitni za računske zadatke s opcijama "-O2 -mfpmath \u003d sse" je oko ~ 5%
Svi podaci u članku predviđaju na temelju rezultata određenog skupa referentnih vrijednosti.
Ispod je opis opcija korištenih u članku. Potpuni opis (na engleskom): http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Optimize-Options.html "
  • "-Brzo" slično "-O3 -brza matematika" omogućuje višu razinu optimizacija i agresivniju optimizaciju za aritmetičke izračune (na primjer, stvarno ponovno pridruživanje)
  • optimizacije za više modula "-flto"
  • 32-bitni način rada "-m32"
  • "-mfpmath \u003d sse" omogućuje upotrebu XMM registara u stvarnoj aritmetici (umjesto stvarnog stoga u načinu x87)
  • "-funroll-petlje" omogućuje odmotavanje petlji

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

Transport je grana materijalne proizvodnje koja prevozi ljude i robu. u strukturi društvene proizvodnje prijevoz se odnosi na proizvodnju materijalnih usluga.

Primjećuje se da se značajan dio logističkih operacija na putu kretanja protoka materijala od primarnog izvora sirovina do krajnje potrošnje provodi pomoću različitih vozila. Troškovi ovih operacija iznose do 50% ukupnih logističkih troškova.

Prema namjeni razlikuju se dvije glavne skupine prijevoza: Javni prijevoz grana je nacionalnog gospodarstva koja zadovoljava potrebe svih sektora nacionalnog gospodarstva i stanovništva u prijevozu robe i putnika. Javni prijevoz služi cirkulaciji i stanovništvu. Često se naziva magistrala (autocesta je glavna, glavna linija u nekom sustavu, u ovom slučaju, u sustavu komunikacijskih linija). Koncept javnog prijevoza obuhvaća željeznički prijevoz, vodni prijevoz (morski i riječni), automobilski, zračni i cjevovodni prijevoz).

Nejavni prijevoz - unutarindustrijski prijevoz, kao i vozila svih vrsta koja pripadaju neprometnim organizacijama.

Organizacija kretanja robe nejavnim prijevozom predmet je proizvodne logistike. Problem odabira distribucijskih kanala rješava se u području distribucijske logistike.

Dakle, postoje sljedeće glavne vrste prijevoza:

željeznička pruga

rijeka unutarnjeg plovnog puta

automobil

zrak

cjevovod

Svaki od načina prijevoza ima specifične značajke u smislu upravljanja logistikom, prednosti i nedostatke koji određuju mogućnosti njegove uporabe u logističkom sustavu. Različite vrste prijevoza čine prometni kompleks. Transportni kompleks Rusije formiraju pravne i fizičke osobe registrirane na njegovom području - poduzetnici koji obavljaju prijevozne i špediterske poslove na svim vrstama prijevoza, projektiranju, izgradnji, popravcima i održavanju željeznica, autocesta i građevina na njima, cjevovoda, radova vezanih uz održavanje plovnih hidrauličkih građevina, vode i dišnih puteva komunikacije od znanstveno istraživanje i osposobljavanje osoblja koje je dio transportnog sustava, poduzeća koja proizvode vozila, kao i organizacije koje obavljaju druge poslove povezane s transportnim procesom. TC Rusije više je od 160 tisuća km glavnih željezničkih i pristupnih cesta, 750 tisuća km cesta s tvrdom podlogom, 1,0 milijuna km morskih brodskih linija, 101 tisuću kilometara unutarnjih plovnih putova, 800 tisuća km zračnih linija. Samo se putem ovih komunikacija svakodnevno prevozi oko 4,7 milijuna tona tereta (od 2000. godine) javnim prijevozom; više od 4 milijuna ljudi radi u TC-u, a udio prometa u bruto domaćem proizvodu zemlje iznosi oko 9%. Dakle, promet je bitan dio infrastrukture gospodarstva i cjelokupnog društvenog i proizvodnog potencijala naše zemlje.

Stol 1 (4, 295) Dane su razmjerno logističke karakteristike različitih vrsta prijevoza.

Tablica 1. Karakteristike načina prijevoza

Vrsta prijevoza

prednosti

nedostaci

željeznička pruga

Visoka nosivost i nosivost. Neovisnost od klimatskih uvjeta, doba godine i dana.

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

Ograničeni broj prijevoznika. Velika kapitalna ulaganja u proizvodnu i tehničku bazu. Velika potrošnja materijala i potrošnja energije u transportu. Mala dostupnost krajnjim prodajnim mjestima (potrošnja).

Nedovoljno visoka sigurnost tereta.

Mogućnost prijevoza između sadržaja. Niska cijena prijevoza na velike udaljenosti. Visoka nosivost i nosivost. Mali kapitalni intenzitet prijevoza.

Ograničeni prijevoz.

Niska brzina isporuke (dugo vrijeme prijevoza).

Ovisnost o geografskim, navigacijskim i vremenskim uvjetima.

Potreba stvaranja složene lučke infrastrukture.

Unutarnja voda (rijeka)

Visoka nosivost na dubokim rijekama i vodnim tijelima.

Niska cijena prijevoza. Niski kapitalni intenzitet.

Ograničeni prijevoz. Mala brzina isporuke tereta.

Ovisnost o neravnoj dubini rijeka i rezervoara, uvjetima plovidbe. Sezonska. Nedovoljna pouzdanost prijevoza i sigurnost tereta.

automobil

Visoka dostupnost.

Mogućnost dostave tereta "od vrata do vrata"

Visoka upravljivost, fleksibilnost, dinamičnost. Velika brzina isporuke. Sposobnost korištenja različitih ruta i shema dostave.

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

Loša izvedba. Ovisnost o vremenu i stanju na cesti. relativno visoki troškovi prijevoza na velike udaljenosti.

Nedovoljna ekološka čistoća.

Zrak

Najveća brzina isporuke tereta. Visoka pouzdanost.

Najveća sigurnost tereta.

Najkraći putovi prijevoza.

Visoki troškovi prijevoza, najviše tarife među ostalim vrstama prijevoza. Veliki kapitalni intenzitet, potrošnja materijala i energije u transportu. Ovisnost o vremenskim uvjetima. Nedovoljna geografska dostupnost.

cjevovod

Niska cijena. Visoke performanse (propusnost). Visoka sigurnost tereta. Niskog intenziteta kapitala.

Ograničene vrste tereta (plin, naftni proizvodi, emulzije sirovina). Nedovoljna dostupnost male količine prevezene robe.

Dakle, prije svega, menadžer logistike mora odlučiti hoće li stvoriti vlastiti vozni park ili će koristiti unajmljena vozila (javna ili privatna). Pri odabiru alternative obično polaze od određenog sustava kriterija koji uključuje: Troškove stvaranja i upravljanja vlastitim voznim parkom. Troškovi plaćanja usluga prijevoza, špedicije i ostali logistički posrednici u prijevozu Brzina prijevoza

Kvaliteta prijevoza (pouzdanost isporuke, sigurnost tereta itd.)

U većini slučajeva proizvodne tvrtke koriste usluge specijaliziranih prijevozničkih tvrtki.