Să explorăm parametrii gcc. Opțiuni optime pentru x86 GCC O scurtă lecție de istorie

GCC este un compilator de optimizare disponibil gratuit pentru limbajele C, C++.

Program gcc, lansat din linie de comandă, este un supliment pentru un grup de compilatoare. În funcție de extensiile de nume de fișiere transmise ca parametri și opțiuni suplimentare, gcc lansează preprocesoarele, compilatoarele, linkurile necesare.

Fișiere cu extensia .cc sau .C sunt considerate fișiere în limbajul C++, fișiere cu extensia .c ca programe în limbaj C și fișiere cu extensia .o sunt considerate obiective.

Pentru a compila codul sursă C++ găsit în fișier F.ccși creați un fișier obiect F.o, trebuie să rulați comanda:

Gcc -c F.cc

Opțiunea -c înseamnă „numai compilare”.

Pentru a lega unul sau mai multe fișiere obiect derivate din cod sursă - F1.o, F2.o, ... - într-un singur fișier executabil F, trebuie să introduceți comanda:

Gcc -o F F1.o F2.o

Opțiunea -o specifică numele fișierului executabil.

Puteți combina doi pași de procesare - compilare și legare - într-unul singur stadiul general folosind comanda:

Gcc -o F F1.cc ... -lg++

- posibile opțiuni suplimentare de compilare și legătură. Opțiunea –lg++ indică necesitatea includerii bibliotecii standard a limbajului C++, - posibile biblioteci suplimentare.
Odată legat, va fi creat un fișier executabil F, care poate fi rulat folosind comanda

./F

- o listă de argumente ale liniei de comandă pentru programul dvs.
Bibliotecile sunt adesea folosite în timpul procesului de conectare. O bibliotecă este o colecție de fișiere obiect grupate într-un singur fișier și indexate. Când comanda link întâlnește o bibliotecă în lista de fișiere obiect de conectat, verifică dacă fișierele obiect legate conțin deja apeluri la funcții definite într-unul dintre fișierele de bibliotecă. Dacă sunt găsite astfel de funcții, apelurile corespunzătoare sunt asociate cu codul fișierului obiect din bibliotecă. Bibliotecile pot fi incluse folosind opțiunea -lname. În acest caz, în directoare standard, cum ar fi /lib , /usr/lib, /usr/local/lib biblioteca va fi căutată într-un fișier numit libname.a. Bibliotecile ar trebui să fie listate după fișierele sursă sau obiect care conțin apeluri la funcțiile corespunzătoare.

Opțiuni de compilare

Dintre numeroasele opțiuni de compilare și legare, cele mai frecvent utilizate sunt:

Opţiune Scop
-c Această opțiune înseamnă că este necesară doar compilarea. Din fișierele sursă ale programului, fișierele obiect sunt create în formular nume.o. Nu se efectuează nici un aspect.
-Dname=valoare Definiți numele în programul compilat ca valoare a lui v alue. Efectul este același cu a avea o linie #definiți valoarea numelui la începutul programului. Parte =valoare poate fi omis, caz în care valoarea implicită este 1.
-o nume-fișier Utilizare nume de fișier ca nume pentru fișierul creat.
-numele Utilizați biblioteca libname.so când conectați
-Llib-cale
-Includ-calea
Adăugați lib-path și include-path la directoarele de căutare standard pentru biblioteci și, respectiv, fișiere de antet.
-g Plasați informațiile de depanare pentru depanator într-un obiect sau fișier executabil gdb. Opțiunea trebuie specificată atât pentru compilare, cât și pentru conectare. În combinație –g Este recomandat să utilizați opțiunea de dezactivare a optimizării -O0(vezi mai jos)
-MM Dependențe de ieșire pe fișierele antet utilizate într-un program C sau C++ într-un format potrivit pentru utilitar face. Nu sunt create obiecte sau fișiere executabile.
-pag Plasați instrucțiuni de profilare într-un obiect sau fișier executabil pentru a genera informații utilizate de utilitar gprof. Opțiunea trebuie specificată atât pentru compilare, cât și pentru conectare. Asamblat cu opțiune -pag Programul generează un fișier de statistici atunci când este lansat. Program gprof Pe baza acestui fișier, creează o transcriere care indică timpul petrecut pentru îndeplinirea fiecărei funcții.
-Perete Afișează mesaje despre orice avertismente sau erori care apar în timpul compilării programului.
-O1
-O2
-O3
Diverse niveluri de optimizare.
-O0 Nu optimizați. Dacă utilizați mai multe -O opțiuni cu sau fără numere de nivel, ultima astfel de opțiune este valabilă.
-Eu Folosit pentru a adăuga propriile directoare pentru a căuta fișiere antet în timpul procesului de construire
-L Transmis la linker. Folosit pentru a adăuga propriile directoare de căutare în bibliotecă în timpul procesului de construire.
-l Transmis la linker. Folosit pentru a adăuga propriile biblioteci pentru a fi căutate în timpul procesului de construire.

Sistemul de operare Linux a apărut pentru prima dată doar ca nucleu de sistem. Din păcate, nucleul în sine nu este foarte util; programele necesită înregistrare, gestionare a fișierelor, compilare de programe noi etc. Pentru a face sistemul util, Proiectul GNU a adăugat diverse caracteristici. Erau clone ale unor programe similare disponibile în sisteme UNIX și UNIX-like din acea vreme. Transformarea Linux într-un sistem asemănător UNIX a stabilit primele standarde pentru Linux, oferind programatorilor C un mediu de lucru familiar.

Diferiți dezvoltatori UNIX (și mai târziu Linux) și-au adăugat propriile extensii la comenzile și utilitățile pe care le-au inclus în sistem, iar structura sistemelor de fișiere pe care le-au folosit a fost, de asemenea, ușor diferită. Toate acestea au făcut dificilă crearea de aplicații care să poată rula pe sisteme diferite. Mai mult, programatorul nici măcar nu se putea baza pe funcționalitatea sistemului implementată în același mod sau pe fișierele de configurare stocate în aceeași locație.

A devenit clar că standardizarea era necesară pentru a menține asemănarea sistemelor UNIX, iar o astfel de muncă este acum în curs.

De-a lungul timpului, nu numai că standardele au avansat, dar sistemul de operare Linux a fost îmbunătățit într-un ritm impresionant de către comunitate, susținută de organizații comerciale precum Red Hat și Canonical și chiar de dezvoltatori non-Linux, precum IBM. Pe măsură ce Linux a evoluat, împreună cu dezvoltarea unei colecții de compilatoare, gcc nu numai că a menținut standardele relevante, dar a definit și noi standarde în cazul în care cele existente s-au dovedit a fi ineficiente. De fapt, pe măsură ce sistemul de operare Linux și software-ul și utilitățile asociate acestuia au devenit din ce în ce mai populare, dezvoltatorii de sisteme UNIX au început să facă modificări produselor lor pentru a le face mai compatibile cu sistemul de operare Linux.

În acest ultim capitol, ne vom uita la standardele Linux, concentrându-ne pe domeniile pe care trebuie să le cunoașteți pentru a nu numai să scrieți aplicații care rulează pe sistemele dvs. Linux după ce le actualizați, ci și să creați cod care poate fi portabil. altor distribuții Linux și poate în sisteme asemănătoare UNIX, asigurând astfel partajarea programelor dvs.

În special vom acoperi următoarele subiecte:

□ Standard limbaj de programare C;

□ Standardele UNIX, în special POSIX, dezvoltate de IEEE, și Specificația Unică UNIX, dezvoltată de Open Group;

□ dezvoltarea de către Free Standards Group, în special Linux Standard Base, care definește aspectul sistemului de fișiere standard Linux.

Un bun punct de plecare pentru înțelegerea standardelor specifice sistemului de operare Linux este Linux Standard Base (LSB), care poate fi găsită pe site-ul Web al Fundației Linux la adresa http://www.linux-foundation.org/.

Nu vom intra în detaliu cu privire la conținutul standardelor, dintre care multe sunt comparabile ca scop cu această carte. Dorim să evidențiem standardele cheie pe care ar trebui să le cunoașteți, să vă oferim un scurt istoric al modului în care s-au dezvoltat aceste standarde și să vă ajutăm să decideți care dintre ele ar putea fi utile atunci când scrieți propriile programe.

limbaj de programare C

Limbajul de programare C este limbajul de programare de facto al sistemului de operare Linux, prin urmare, pentru a scrie programe C pentru Linux, trebuie să înțelegeți puțin despre originile sale, să aflați cum s-a schimbat limbajul și, cel mai important, să înțelegeți modul în care programele sunt verificate pentru conformitatea cu standardele.

O scurtă lecție de istorie

Pentru cei care nu sunt foarte pasionați de istorie, nu vă faceți griji: această carte este despre programare, nu despre istorie, așa că recenzia va fi foarte scurtă.

Limbajul de programare C a apărut la începutul anilor 1970 și s-a bazat parțial pe limbajul de programare anterior BCPL și pe extensii ale limbajului B Dennis M. Ritchie a scris un manual de utilizare pentru limbaj în 1974, iar în aceeași perioadă a fost folosit C ca. un limbaj de programare pentru a reelabora nucleul UNIX pe computerele PDP-11. În 1978, Brian W. Kernighan și Ritchie au scris manualul clasic al limbajului, Limbajul de programare C.

Foarte repede limbajul a câștigat o mare popularitate, datorită, fără îndoială, parțial creșterii rapide a popularității sistemelor UNlX, dar și capacităților și sintaxei sale ușor de înțeles. Sintaxa limbajului C a continuat să evolueze într-o manieră consecventă, dar pe măsură ce s-a schimbat din ce în ce mai mult față de descrierea originală dată în carte, a devenit clar că era nevoie de un standard care să fie în concordanță cu utilizarea modernă și care să fie mai riguros.

În 1983, ANSI (American National Standards Institute) a fondat comitetul de standarde X3J11 pentru a dezvolta o definiție clară și riguroasă a limbii. Pe parcurs, ambele organizații au făcut modificări minore în limbă, în special oferindu-i capacitatea mult așteptată de a declara tipurile de parametri, dar mai ales comitetul a adus pur și simplu claritate și justificare definiției existente a ceea ce a constituit o variantă lingvistică comună a limbii. . Standardul final a fost publicat în 1989 ca ANSI Standard Programming Language C, X3.159-1989, sau mai pe scurt C89, uneori denumit C90. (Acest din urmă s-a transformat în standardul ISO/IEC 9899:1990, Limbaje de programare - C. Ambele standarde sunt formal identice.)

Ca și în cazul majorității standardelor, publicarea nu a pus capăt lucrărilor comitetului, care a continuat să elimine unele dintre inexactitățile găsite în specificație și a început lucrul la o nouă versiune a standardului în 1993, numită C9X. Comitetul a publicat, de asemenea, ajustări minore și actualizări ale standardului existent în 1994-1996.

Versiune nouă standardul a fost realizat în anii 1990. și a devenit oficial standardul C99; a fost adoptat de ISO ca ISO/IEC 9899:1999. Există încă un comitet J11 activ care supraveghează standardizarea limbajului C și a bibliotecilor sale, dar acum funcționează în cadrul grupului Comitetului Internațional pentru Standardele Tehnologiei Informației. tehnologia de informație). Informații suplimentare Pentru informații despre munca de standardizare C, consultați site-ul web http://j11.incits.org/.

Colecția de compilatori GNU

După dezvoltarea editorului Emacs (da, ne place Emacs), următoarea realizare majoră a proiectului GNU, așa cum este menționat în capitolul 1, a devenit un compilator C complet gratuit, gcc, primul versiunea oficială care a fost lansat în 1987.

Numele gcc a reprezentat inițial GNU C Compiler (compilatorul C al proiectului GNU), dar din moment ce runtimeul de bază al compilatorului suportă acum multe alte limbaje de programare, cum ar fi C++, Objective-C, FORTRAN, Java și Ada, precum și biblioteci pentru acestea. limbi, definiția a fost înlocuită cu mai potrivită GNU Compiler Collection (colecție de compilatoare GNU).

gcc a fost întotdeauna și pare să rămână compilatorul standard pentru Linux și C sau C++, limbajul principal pentru scrierea programelor în sistemul de operare Linux. Pagina sursă gcc poate fi găsită la http://gcc.gnu.org/.

Compilatorul GNU C a ținut întotdeauna o evidență bună a dezvoltării standardului limbajului C, deși permite unele extensii ale limbajului și, desigur, există întârzieri minore, la fel ca în cazul aproape tuturor compilatoarelor, între lansarea standardului și lansarea versiunilor de compilator care urmează exact specificația. Uneori se întâmplă opusul, iar gcc anticipează modificări slabe ale standardului, care pot fi, de asemenea, complet confuze. gcc are o serie de linie de comandă și alte opțiuni care vă permit să specificați versiunea standardului limbajului C la care trebuie să se conformeze compilatorul, precum și o serie de alte opțiuni pentru a controla cât de pretențios sau strict este compilatorul.

opțiunile gcc

Acum că știți ceva despre standardul C, să ne uităm la opțiunile pe care le oferă compilatorul gcc pentru a asigura conformitatea cu standardul C în limba pe care o scrieți. Există trei moduri de a vă asigura că codul dvs. C este compatibil cu standardele și nu prezintă defecte: opțiuni care controlează versiunea standardului la care intenționați să vă conformați, definiții care controlează fișierele de antet și opțiuni de avertizare care declanșează o verificare mai strictă a codului.

gcc are o gamă largă de opțiuni și aici le vom lua în considerare doar pe cele pe care le considerăm cele mai importante. O listă completă de opțiuni poate fi găsită în paginile de manual online gcc. De asemenea, vom discuta pe scurt câteva dintre opțiunile directivei

, care poate fi aplicat; De obicei, acestea ar trebui să fie specificate în codul sursă înaintea oricărei linii de directivă sau definite pe linia de comandă gcc. Ați putea fi surprins de câte opțiuni există pentru a selecta ce standard să utilizați, mai degrabă decât să bifați pur și simplu un semnalizare pentru a forța utilizarea standardului actual. Motivul este că multe programe mai vechi se bazează pe comportamentul istoric al compilatorului și ar necesita o muncă semnificativă pentru a le actualiza la cele mai recente standarde. Rareori, dacă vreodată, veți dori să vă actualizați compilatorul pentru a-l determina să rupă codul care rulează. Pe măsură ce standardele se schimbă, este important să poți lucra împotriva unui anumit standard, chiar dacă nu este cel mai mare ultima versiune standard

Chiar dacă scrieți un program mic pentru uz personal, unde respectarea standardelor poate să nu fie atât de importantă, este adesea logic să includeți avertismente gcc suplimentare pentru a forța compilatorul să caute erori în codul dvs. înainte de a executa programul. Acest lucru este întotdeauna mai eficient decât executarea codului pas cu pas în depanator și întrebarea unde ar putea fi problema. Compilatorul are multe opțiuni care merg dincolo de simpla verificare a standardelor, cum ar fi capacitatea de a detecta codul care îndeplinește standardul, dar poate avea o semantică îndoielnică. De exemplu, un program poate avea un ordin de execuție care permite accesarea unei variabile înainte de a fi inițializată.

Dacă trebuie să scrieți un program pentru utilizare partajată, având în vedere gradul de conformitate cu standardul și tipurile de avertismente ale compilatorului pe care le considerați suficiente, este foarte important să depuneți puțin mai mult efort și să vă compilați codul fără avertismente la toate. Dacă lași să apară unele avertismente și iei obiceiul de a le ignora, într-o zi poate apărea un avertisment mai serios pe care riști să-l ratezi. Dacă codul dvs. se compila întotdeauna fără mesaje de avertizare, o nouă avertizare vă va atrage inevitabil atenția. Compilarea codului fără avertismente este un obicei bun de adoptat.

Opțiuni de compilare pentru urmărirea standardelor- Aceasta este cea mai importantă opțiune de standarde și obligă compilatorul să acționeze în conformitate cu standardul de limbaj ISO C90. Dezactivează unele extensii gcc care nu sunt conforme cu standardul, dezactivează comentariile în stil C++ () în programele C și permite gestionarea trigrafelor ANSI (secvențe cu trei caractere). În plus, conține macrocomanda __, care dezactivează unele extensii din fișierele antet care nu sunt compatibile cu standardul. Standardul adoptat se poate modifica în versiunile ulterioare ale compilatorului. - Această opțiune oferă un control mai fin asupra standardului utilizat, oferind un parametru care specifică exact standardul necesar. Mai jos sunt principalele opțiuni posibile: - suportă standardul C89; - suportă cea mai recentă versiune a standardului ISO, C90; - acceptă standardul C89, dar permit unele extensii GNU și altele funcţionalitate C99. În versiunea 4.2 a gcc, această opțiune este implicită. Opțiuni pentru urmărirea standardului în directive defini

Există constante (

), care poate fi specificat prin opțiuni de pe linia de comandă sau ca definiții în codul sursă al programului. În general, considerăm că acestea folosesc linia de comandă a compilatorului. - obligă utilizarea standardului ISO C. Determinat când opțiunea este specificată pe linia de comandă a compilatorului. - Activează funcționalitatea definită de IEEE Std 1003.1 și 1003.2. Vom reveni la aceste standarde mai târziu în acest capitol. - include funcționalitate sisteme BSD. Dacă sunt în conflict cu definițiile POSIX, definițiile BSD au prioritate. - Permite o gamă largă de proprietăți și funcții, inclusiv extensii GNU. Dacă aceste definiții sunt în conflict cu definițiile POSIX, acestea din urmă au prioritate. Opțiuni de compilare pentru ieșirea de avertizare

Aceste opțiuni sunt transmise compilatorului din linia de comandă. Și din nou le vom enumera doar pe cele principale, lista completa pot fi găsite în interactiv ghid de referință gcc.

Aceasta este cea mai puternică opțiune pentru verificarea purității codului C În plus față de activarea opțiunii de verificare standard C, dezactivează unele constructe C tradiționale care sunt interzise de standard și invalidează toate extensiile GNU la standard. Această opțiune ar trebui folosită pentru a maximiza portabilitatea codului dvs. C. Dezavantajul este că compilatorul este foarte preocupat de curățarea codului dvs. și, uneori, trebuie să vă grăbiți pentru a scăpa de puținele avertismente rămase. - verifică corectitudinea tipurilor de argument ale funcţiilor familiei. - verifică prezența parantezelor, chiar și acolo unde nu sunt necesare. Această opțiune este foarte utilă pentru a verifica dacă structurile complexe sunt inițializate conform intenției. - verifică prezența variantei în instrucțiuni, ceea ce este considerat în general un stil de programare bun. - verifică diverse cazuri, de exemplu, funcții statice declarate dar nedescrise, parametri neutilizați, rezultate aruncate. - include majoritatea tipurilor de avertismente gcc, inclusiv toate opțiunile anterioare - (numai că nu sunt acoperite). Cu ajutorul lui, este ușor să obțineți cod curat.
Nota

Există multe mai multe opțiuni avansate de avertizare disponibile, consultați paginile web gcc pentru detalii. În general, recomandăm utilizarea

; acesta este un compromis bun între verificarea și asigurarea codului programului calitate superioară, și necesitatea compilatorului de a scoate o masă de avertismente banale, care devin greu de redus la zero.

Interfețe și bază de standarde Linux

Acum vom trece la un nivel și vom trece de la codul C la să ne uităm la interfețe ( funcțiile sistemului) furnizate de sistemul de operare. Acest nivel de standardizare are diferite componente: funcții furnizate de biblioteci și apeluri de sistem implementate de sistemul de operare la un nivel scăzut. Ambele au două niveluri de detaliu: ce interfețe sunt reprezentate și o definiție a ceea ce face fiecare interfață.

Documentul definitoriu în acest domeniu pentru sistemul de operare Linux este Linux Standards Base (LSB, standarde pentru sistemele de operare bazate pe Linux), care poate fi găsit pe site-urile Web http://mvw.linuxbase.org sau http://www.linux-foundation.org/en/LSB. Mai multe versiuni ale standardelor au fost deja lansate, iar munca continuă.

O listă a distribuțiilor certificate poate fi găsită la http://www.linux-foundation.org/en/Products. Diferite versiuni de Red Hat, SUSE și Ubuntu sunt certificate, dar rețineți că după lansarea distribuției, poate trece ceva timp până la obținerea certificării. Site-ul Web are o listă de distribuții care sunt în curs de testare sau au nevoie doar de unele actualizări pentru a trece testele de certificare.

Linux Standards Base (începând cu versiunea 3.1) definește trei domenii pentru testarea conformității:

□ kernel - biblioteci principale, utilitare și locația componentelor cheie ale sistemului de fișiere;

□ C++ - biblioteci C++;

□ desktop - fișiere suplimentare pentru instalări desktop, în principal biblioteci grafice diferite.

În specificație, suntem cel mai interesați de nucleu.

Standardul LSB acoperă o serie de domenii în propria sa documentație, dar se referă și la standarde externe pentru definiții specifice de interfață. Standardul acoperă următoarele domenii:

□ formate de fișiere obiect pentru compatibilitate binară;

□ standarde de legătură dinamică;

□ biblioteci standard, atât biblioteci de bază, cât și biblioteci X Window System;

□ shell de comandă și alte programe de linie de comandă;

□ mediu de rulare, inclusiv utilizatori și grupuri;

□ inițializarea sistemului și nivelurile de rulare.

În acest capitol, vom discuta doar bibliotecile standard, utilizatorii și inițializarea sistemului.

Biblioteci standard LSB

Documentația Linux Standard Base definește în două moduri interfețele care trebuie să fie prezente. Pentru unele funcții, în cea mai mare parte implementate de biblioteca GNU Project C sau care tind să fie standarde numai pentru Linux, atât interfața, cât și comportamentul acesteia sunt definite. Pentru alte interfețe, în special cele cu un cadru asemănător UNIX, standardul afirmă pur și simplu că o astfel de interfață trebuie să fie prezentă și trebuie să se comporte așa cum este definit de un alt standard, de obicei Common Application Environment (CAE). mediu de aplicație) sau, mai frecvent, specificația unică UNIX, care este disponibilă pe site-ul web Open Group http://www.opengroup.org. Unele părți pot fi găsite (în prezent este necesară înregistrarea) la http://www.unix.org/online.html.

Din păcate, standardele Linux și UNIX care stau la baza au un trecut mai degrabă în carouri și sunt prea multe gamă largă, deși în general diferitele versiuni sunt aproape compatibile.

O scurtă lecție de istorie

Sistemul de operare UNIX s-a născut la sfârșitul anilor 1960. Divizia Bell Laboratories a AT&T atunci când Ken Thompson și Dennis Ritchie au scris un sistem de operare destinat inițial doar pentru uz personal, pe care l-au numit Unics. Cumva, numele s-a schimbat în UNIX. AT&T a permis universităților să ia codul sursă pentru propria lor dezvoltare, iar UNIX a devenit rapid incredibil de popular datorită structurii sale logice foarte clare și ideilor puternice. Disponibilitatea codului sursă ar fi trebuit să fie un stimulent semnificativ, deoarece le-a permis programatorilor să facă modificări și să experimenteze.

Sistemul de operare BSD a fost o opțiune care a rezultat din munca depusă la Universitatea din California din Berkeley, care a pus foarte mult accent pe organizarea și întreținerea rețelei.

Când AT&T a început să facă din UNIX un sistem comercial, ceea ce sa întâmplat mai ales la mijlocul anilor 1980, a numit lansările sistemului UNIX System, iar cel mai popular a fost UNIX System V.

Au apărut multe alte variante, prea multe pentru a fi enumerate aici, toate cu mici variații față de standardele de bază și unele completări, deoarece companiile au încercat să adauge valoare produsului prin crearea propriilor extensii.

Lucrurile s-au complicat cu adevărat când AT&T a vândut afacerea UNIX către Novell, care a decis să o înceteze în 1994, iar proprietatea asupra drepturilor și mărcilor comerciale a devenit o problemă incertă, supusă diverselor procese.

În 1988, IEEE (Institutul de Ingineri Electrici și Electronici, Institutul de Ingineri Electrici și Electronici, http://www.ieee.org) a lansat primul set de standarde: POSIX sau IEEE 1003 - standarde care urmau să fie specificația definitorie a unei interfețe portabile pentru sistemele de operare ale computerelor. Deși este un standard bun și bine definit, POSIX este, de asemenea, o specificație a nucleului cu un domeniu de aplicare foarte limitat.

În 1994, X/Open Company, o organizație fără aprovizionare, a lansat un set mai cuprinzător de specificații, X/Open CAE sau Common Applications Environment, care este o extensie a standardelor IEEE POSIX și este formal identic cu acestea în multe zone. X/Open a fuzionat ulterior cu OSF (Free Software Foundation). software) pentru constituirea Grupului Deschis; pagina sa de internet de pornire se află la http://www.opengroup.org/. Standardul CAE a fost revizuit și lansat în 2002 ca specificație unică UNIX, versiunea 3, dezvoltată de Open Group.

Această specificație este cea mai des menționată în baza standardelor Linux.

Nota

Trebuie remarcat faptul că „Linux” este o marcă comercială deținută de Linus Torvalds. Cm. http://www.linuxmark.org/.

Aplicarea standardului LSB la biblioteci

Destul despre istoria creării standardelor. Ce înseamnă pentru oameni scrierea de programeîn C (sau C++), cerința pentru portabilitatea lor?

În primul rând, trebuie să vă asigurați că funcția de bibliotecă pe care o utilizați este în standardul LSB. Dacă nu există, este posibil să faci ceva care nu se va transfera cu ușurință într-un alt sistem și ar trebui să cauți o modalitate standard de a implementa problema pe care încerci să o rezolvi. Poate că merită încercat Comanda Linux apropos, care caută în paginile de ajutor online linkuri relevante.

În al doilea rând, și mai dificil, ar trebui să vă asigurați că comportamentul funcției pe care o utilizați este inclus în standard și că nu vă bazați pe un comportament care nu este descris în standard. Poate fi necesar să vă referiți la specificația UNIX unică pentru aceasta dacă utilizarea funcției nu este definită în standardul LSB. Foarte cale bună verificați comportamentul nedefinit sau potențial eronat - consultați manualul online Linux. Multe dintre paginile sale au o secțiune „BUGS”, care este o sursă neprețuită de informații despre unde în Linux un anumit apel nu implementează pe deplin standardele sau unde există defecte și ciudatenii în comportament.

Utilizatori și grupuri LSB

Această secțiune a standardului este precisă, concisă și clară. Următoarele sunt câteva dintre cerințele standardului.

□ Specificația cere ca, pentru a obține informații detaliate despre utilizator, să nu citiți niciodată fișiere precum /etc/passwd direct, ci să utilizați întotdeauna apeluri standard de bibliotecă, de ex.

, sau utilități standard, de exemplu.

□ Standardul necesită un utilizator numit root în grupul rădăcină, care este un administrator de sistem cu privilegii sau drepturi de acces complete. De asemenea, găsim în standard o serie de nume opționale de utilizatori și grupuri care nu ar trebui niciodată folosite aplicații standard; sunt destinate a fi utilizate de distribuții.

□ Standardul mai precizează că ID-urile mai mici de 100 sunt ID-uri de sistem conturi, intervalul 100-499 este ocupat de administratorii de sistem și scripturile de post-instalare și, în sfârșit, numerele de identificare 500 și mai sus sunt destinate conturilor de utilizator obișnuite.

În general, majoritatea programatorilor Linux ar trebui să fie conștienți de cerințele standardelor legate de utilizator.

Inițializarea sistemului LSB

Zona de inițializare sau pornire a sistemului a fost întotdeauna, cel puțin pentru noi, o sursă de îngrijorare din cauza diferențelor subtile de distribuție.

Linux a moștenit de la sistemele de operare asemănătoare UNIX ideea de niveluri de execuție, sau niveluri de execuție, care definesc serviciile care rulează constant pe sistem. În tabel 18.1 oferă definiții standard pentru sistemul de operare Linux.


Tabelul 18.1

Nivel de alergare Descriere
0 Halt. Folosit ca stare logică la care se ajunge atunci când sistemul se oprește
1 Modul pentru un singur utilizator. Este posibil ca alte directoare decât / (rădăcină) să nu fie montate și să nu aibă suport de rețea. Utilizat de obicei pentru întreținerea sistemului
2 Modul multiplayer, dar fără suport online
3 Multiplayer obișnuit cu suport online folosind un ecran de conectare în modul text
4 Rezervat
5 Multiplayer online obișnuit folosind ecranul grafic de conectare
6 Pseudo-nivel folosit pentru repornire

Standardul LSB oferă aceste niveluri, dar nu necesită utilizarea lor, deși sunt foarte comune.

Nivelurile de execuție însoțitoare este un set de scripturi de inițializare care sunt utilizate pentru a porni, opri și reporni serviciile. În trecut, acestea erau stocate în diferite locuri în directorul /etc, adesea în /etc/init.d sau /etc/rc.d/init.d. Această varietate a provocat adesea confuzie, deoarece utilizatorii care au schimbat distribuțiile nu au putut găsi scripturile de inițializare în locurile obișnuite, iar instalarea programelor ar eșua dacă ar încerca să execute scriptul de inițiere din directorul greșit.

Standardul LSB 3.1 definește directorul /etc/init.d ca locație pentru stocarea scripturilor init, dar permite și ca acest director să fie o legătură către o altă locație din sistem.

Fiecare script din directorul /etc/init.d are un nume asociat serviciului pe care îl oferă. Deoarece toate serviciile de sistem de operare Linux trebuie să partajeze același spațiu de nume, este important ca aceste nume să fie unice. De exemplu, viața va fi dificilă dacă serviciile MySQL și PostgreSQL decid să-și numească scripturile „bază de date”. Pentru a rezolva acest conflict, există un alt set de standarde. Acesta este standardul Autorității pentru nume și numere atribuite (LANANA), care poate fi găsit pe site http://www.lanana.org/. Din fericire, va trebui să știți foarte puține despre acest standard, cu excepția faptului că stochează o listă de nume de scripturi și pachete înregistrate, ușurând viața utilizatorilor. sisteme Linux.


Scriptul de pornire trebuie să accepte un parametru care controlează ceea ce face. Standardul definește parametrii enumerați în tabel. 18.2.


Tabelul 18.2

Parametru Sens
Pornește (sau repornește) un serviciu
Oprește serviciul
Repornește serviciul; implementat de obicei ca o simplă oprire a unui serviciu, urmată de pornirea acelui serviciu
Reinstalează serviciul prin reîncărcarea parametrilor fără a opri efectiv serviciul. Nu toate serviciile acceptă această opțiune, așadar acest parametru este posibil să nu fie disponibil în unele scenarii și, dacă este disponibil, nu are niciun efect
Încearcă să forțeze o reinstalare dacă serviciul o acceptă, dacă nu, repornește serviciul
Imprimă un mesaj text despre starea serviciului și returnează un cod de stare care poate fi folosit pentru a determina starea serviciului

Toate comenzile returnează 0 dacă au succes sau un cod de eroare care indică motivul eșecului. În cazul parametrului

returnează 0 dacă serviciul rulează; toate celelalte coduri înseamnă că serviciul nu rulează dintr-un motiv oarecare.

Dispozitivul standard al sistemului de fișiere

Ultimul standard pe care îl vom analiza în acest capitol este Standardul ierarhiei sistemului de fișiere (FHS). Poate fi găsit la http://www.pathname.com/fhs/.

Scopul acestui standard este de a defini locații tipice de stocare în sistemul de fișiere Linux, astfel încât atât dezvoltatorii, cât și utilizatorii să poată face presupuneri informate despre locația anumitor fișiere. Utilizatori de lungă durată ai sistemelor de operare asemănătoare UNIX pentru o lungă perioadă de timp s-au plâns de diferențele subtile în aspectul sistemului de fișiere, iar standardul FHS propune distribuții Linux o modalitate de a evita repetarea acestui drum intermitent.

La prima vedere, aspectul fișierelor din sistemul Linux poate părea o structură semi-arbitrară de fișiere și directoare bazate pe idei istorice. Acest lucru este parțial adevărat, dar de-a lungul anilor aspectul a evoluat în mod justificat în ierarhia pe care o vedem astăzi. Ideea sa principală este de a împărți fișierele și directoarele în următoarele trei grupuri:

□ fișiere și directoare unice pentru un anumit sistem Linux care rulează, cum ar fi scripturile de pornire și fișierele de configurare;

□ fișiere și directoare care sunt doar în citire și posibil partajate de mai multe sisteme Linux care rulează, cum ar fi executabilele aplicațiilor;

□ directoare care sunt de citire/scriere, dar posibil partajate între Linux care rulează sau alte sisteme de operare, cum ar fi directoarele de acasă ale utilizatorilor.

În această carte, nu suntem prea interesați de partajarea fișierelor între diferiți versiuni Linux deși, în cazul unei rețele de mașini Linux, aceasta este o modalitate excelentă de a vă asigura că există o singură copie a directoarelor programe cheieși partajați-l pe diferite mașini din rețea. Acest lucru este util în special pentru stațiile de lucru fără disc.

Standardul FHS definește structura nivel superior, care are un număr de subdirectoare necesare și mai multe directoare opționale; principalele sunt date în tabel. 18.3.


Tabelul 18.3

Catalog Necesar? Scop
/bin Da Binare importante ale sistemului
/boot Da Fișierele necesare pentru a porni sistemul
/dev Da Dispozitive
/etc Da Fișiere de sistem configuratii
/acasă Nu Directoare pentru fișierele utilizator
/lib Da Biblioteci standard
/media Da Spațiu pentru medii de stocare amovibile, cu subdirectoare separate pentru fiecare tip de suport suportat de sistem
/mnt Da Punct convenabil pentru montarea temporară a dispozitivelor, cum ar fi CD-ROM-uri și unități de memorie flash
/opta Da Software de aplicație suplimentar
/rădăcină Nu fișierele utilizator root
/sbin Da Binare de sistem importante care sunt necesare în timpul procesului de pornire a sistemului
/srv Da Date numai în citire pentru serviciile furnizate de acest sistem
/tmp Da Fișiere temporare
/usr Da Ierarhie auxiliară. În mod tradițional, fișierele utilizator sunt și ele stocate aici, dar în prezent acest lucru este considerat un stil prost și utilizatorului obișnuit nu ar trebui să i se acorde acces de scriere la acest director.
/var Da Date variabile, cum ar fi fișierele jurnal

În plus, pot exista și alte directoare care încep cu lib, deși acest lucru nu este obișnuit. De obicei, veți vedea, de asemenea, un director /lost+found (pentru restaurarea unui sistem de fișiere folosind fsck) și un director /proc, care este un pseudo-sistem de fișiere care oferă o reprezentare a sistemului care rulează. Versiunea actuală a standardului FHS acceptă puternic sistemul de fișiere /proc, dar prezența acestuia nu este necesară. Detaliile referitoare la sistemul /proc depășesc în mare sfera subiectelor discutate în această carte, deși l-am inclus scurtă prezentare generală V Capitolul 3.

□ /bin - Conține fișiere binare care pot fi utilizate atât de utilizatorii root, cât și de cei non-root și sunt importante pentru funcționarea în modul utilizator unic, unde este posibil să nu fie montate alte structuri de directoare. De exemplu, aici puteți găsi, de obicei, comenzi de kernel

și, ca și echipa.

□ /boot - folosit pentru fișierele necesare în timpul pornirii unui sistem Linux. Adesea, acest director este foarte mic, mai mic de 10 MB și este adesea o partiție separată. Acest lucru este foarte util pe sisteme bazate pe PC care au restricții BIOS asupra partiției active care se află în primii 2 sau 4 GB de disc. Având acest director ca o partiție separată, veți avea mai multă flexibilitate atunci când plasați restul partițiilor de disc.

□ /dev - conține fișiere speciale de dispozitiv care sunt mapate pe dispozitive hardware. De exemplu, /dev/had va fi mapat mai întâi la unitate IDE.

□ /etc - conține fișiere de configurare. În mod tradițional, unele binare pot fi găsite aici, dar acest lucru nu mai este adevărat pentru majoritatea sisteme moderne Linux. Cel mai faimos fișier din directorul /etc este probabil fișierul passwd, care conține informații despre utilizator. Alte fișiere utile- fstab cu o listă de opțiuni de montare; gazde cu o listă de mapări de la adrese IP la nume de computer și directorul httpd care conține configurația pentru server Apache.

□ /home - director pentru fișierele utilizator. De obicei, fiecare utilizator din acest director va avea un director cu același nume cu numele de conectare al utilizatorului, iar acesta va fi directorul de conectare implicit. De exemplu, după înregistrare, utilizatorul rick se va găsi aproape sigur în directorul /home/rick.

□ /lib - Conține biblioteci importante partajate și module kernel, în special cele care vor fi necesare atunci când sistemul pornește în modul utilizator unic.

□ /media - conceput ca un director de nivel superior pentru stocarea directoarelor punctelor de montare pentru suporturi amovibile. Scopul este de a putea elimina directoarele de nivel superior inutile, cum ar fi /cdrom și /floppy.

□ /mnt este doar un loc convenabil pentru a monta temporar sisteme de fișiere suplimentare. În mod tradițional, unele distribuții au adăugat subdirectoare în directorul /mnt pentru diverse dispozitive, cum ar fi /cdrom și /floppy, dar preferința actuală este să le plaseze în directorul /media, revenind /mnt la scopul său original - un singur top- locație de nivel pentru suporturi temporare (locație unică de montare temporară de nivel superior).

□ /opt - director pentru furnizorii de software folosit pentru inserare aplicații software adăugat la distribuția de bază. Distribuțiile nu ar trebui să-l folosească pentru a stoca software-ul care face parte din distribuția standard, ci ar trebui lăsat pentru utilizare de către furnizori terți. De obicei, vânzătorii vor crea subdirectoare cu propriile nume și subdirectoare în ele, cum ar fi /bin și /lib, pentru fișierele relevante pentru aplicația lor.

Nota

Prin convenție, multe pachete Open Source Linux folosesc directorul /usr/local pentru instalare.

□ /root este directorul pentru fișierele utilizate utilizator root. Nu face parte din directorul /home din arborele de directoare deoarece este posibil să nu se monteze în modul utilizator unic.

□ /sbin - folosit doar pentru comenzile utilizate de obicei administrator de sistemși este necesar în timpul pornirii sistemului în modul pentru utilizator unic. Aici locuiesc echipele

, Și .

□ /srv - conceput pentru a găzdui date locale în modul doar citire, dar nu este utilizat pe scară largă în prezent.

□ /tmp - folosit pentru fișierele temporare. De obicei, dar nu întotdeauna, este șters atunci când sistemul pornește.

□ /usr este un sistem de fișiere auxiliar destul de complex, care conține de obicei toate comenzile și bibliotecile de tip sistem care nu sunt necesare atunci când sistemul pornește sau în modul utilizator unic. Directorul are multe subdirectoare, cum ar fi /bin, /lib, /X11R6 și /local.

Nota

Când au apărut pentru prima dată sistemele UNIX și Linux, directorul /usr avea și subdirectoare pentru înregistrare, stocare în buffer e-mail etc. Acum toate aceste subdirectoare sunt eliminate din directorul usr și plasate în directorul var. Avantajul acestei abordări este că /usr este acum montabil sistem de fișiere, poate fi partajat de alte sisteme din rețea și este mai puțin susceptibil la deteriorarea sistemului care îl oprește într-un mod necontrolat, cum ar fi o pană de curent.

□ /var - Conține date care se schimbă frecvent, cum ar fi fișiere spool de tipărire, fișiere jurnal de aplicații și directoare spool de e-mail.

gcc (GNU C Compiler) este un set de utilitare pentru compilare, asamblare și legare. Scopul lor este să creeze un fișier executabil gata de rulat într-un format pe care sistemul de operare îl poate înțelege. Pentru Linux, acest format este ELF (Executable and Linking Format) pe x86 (32 și 64 de biți). Dar știi ce pot face unele opțiuni gcc pentru tine? Dacă sunteți în căutarea unor modalități de a optimiza binarul rezultat, de a configura o sesiune de depanare sau pur și simplu de a respecta pașii pe care îi face gcc pentru a vă transforma codul sursă într-un fișier executabil, familiaritatea cu aceste opțiuni este obligatorie. Deci, citește mai departe.

Permiteți-mi să vă reamintesc că gcc face mai mulți pași, nu doar unul. Iată o mică explicație a semnificației lor:

    Preprocesare: se generează cod care nu mai conține directive. Lucruri precum „#if” nu pot fi înțelese de compilator, așa că trebuie traduse în cod real. Macro-urile sunt, de asemenea, extinse în această etapă, făcând codul final mai mare decât originalul.

    Compilare: Se preia codul procesat, se efectuează analize lexicale și sintactice și se generează codul de asamblare. În această fază, gcc emite mesaje de eroare sau de avertizare dacă analizorul găsește erori în timpul analizării codului. Dacă se solicită o optimizare, gcc va continua să analizeze codul dvs. pentru îmbunătățiri și să le manipuleze în continuare. Această lucrare are loc într-un stil cu mai multe treceri, ceea ce arată că uneori este necesară mai mult de o trecere prin cod pentru optimizare.

    Asamblare: sunt acceptate mnemonice de asamblare și sunt produse coduri obiect care conțin coduri de instrucțiuni. Ceea ce este adesea înțeles greșit este că codurile de instrucțiuni nu sunt produse în etapa de compilare, aceasta se face în etapa de asamblare. Rezultatul este unul sau mai multe fișiere obiect care conțin coduri de instrucțiuni care sunt cu adevărat dependente de mașină.

    Conectare: Transformă fișierele obiect în fișiere executabile finale. Numai codurile de operare nu sunt suficiente sistem de operare le-a recunoscut și implementat. Ele ar trebui să fie construite într-o formă mai completă. Acest formular, cunoscut sub numele de format binar, specifică modul în care sistemul de operare încarcă fișierul binar, compune mutarea și efectuează alte lucrări necesare. ELF este formatul implicit pentru Linux pe x86.

    Opțiunile gcc sunt descrise aici, afectând direct și indirect toate cele patru etape, așa că, din motive de claritate, acest articol este structurat după cum urmează:

    Parametrii legati de optimizare

    Parametri legați de apelurile de funcții

    Opțiuni legate de depanare

    Opțiuni legate de preprocesare

    Mai întâi de toate, să aruncăm o privire la instrumentele de ajutor care ne vor ajuta să intrăm în codul final:

    O colecție de utilitare ELF care include programe precum objdump și readelf. Ei scot informații despre ELF pentru noi.

    Grad de eroare = ramuri defecte izolate / ramuri izolate

    Acum să calculăm gradul de eroare pentru fiecare fișier binar. Pentru neoptimizat a fost de 0,5117%, în timp ce optimizatO2 a fost de 0,4323% - în cazul nostru, beneficiul este foarte mic. Beneficiul real poate varia pentru cazurile din lumea reală, deoarece gcc în sine nu poate face mare lucru fără îndrumări externe. Vă rugăm să citiți despre __builtin_expect() în documentația gcc pentru detalii.

Pentru utilizarea corectă gcc, compilatorul C standard pentru Linux, trebuie să înveți opțiunile liniei de comandă. În plus, gcc extinde limbajul C Chiar dacă intenționați să scrieți cod sursă urmând standardul de limbaj ANSI, unele extensii gcc sunt esențiale pentru înțelegerea fișierelor de antet Linux.

Majoritatea opțiunilor din linia de comandă sunt aceleași cu cele utilizate în compilatoarele C Pentru unele opțiuni nu există standarde. În acest capitol, vom acoperi cele mai importante opțiuni care sunt utilizate în programarea de zi cu zi.

Efortul de a respecta standardul ISO C este foarte util, dar datorită faptului că C este un limbaj de nivel scăzut, există situații în care mijloace standard nu suficient de expresiv. Există două domenii în care extensiile gcc sunt utilizate pe scară largă: interfața cu codul de asamblare (acoperit la http://www.delorie.com/djgpp/doc/brennan/) și construirea de biblioteci partajate (vezi Capitolul 8). Deoarece fișierele antet fac parte din bibliotecile partajate, unele extensii apar și în fișierele antet de sistem.

Desigur, există mult mai multe extensii care sunt utile în orice alt tip de programare și pot fi de mare ajutor la codificare. Mai multe informații despre aceste extensii pot fi găsite în documentația gcc în format Texinfo.

5.1. opțiunile gcc

gcc acceptă multe opțiunile de comandă. Din fericire, nu există multe opțiuni despre care trebuie să știți cu adevărat și le vom analiza în acest capitol.

Majoritatea opțiunilor sunt aceleași sau similare cu alte compilatoare, iar gcc include o documentație extinsă despre opțiunile sale, disponibilă prin info gcc (man gcc oferă și aceste informații, dar paginile de manual nu sunt actualizate la fel de frecvent ca documentația Texinfo).

-o nume de fișier Specifică numele fișierului de ieșire. De obicei, acest lucru nu este necesar dacă compilați într-un fișier obiect, adică implicit este înlocuirea nume_fișier.c cu nume_fișier.o. Totuși, dacă creați un executabil, implicit (din motive istorice) acesta este creat sub numele a.out . Acest lucru este util și atunci când doriți să plasați fișierul de ieșire într-un director diferit.
-Cu Compilează fără a lega fișierul sursă specificat pentru linia de comandă. Ca rezultat, un fișier obiect este creat pentru fiecare fișier sursă. Când utilizați make, compilatorul gcc este de obicei apelat pentru fiecare fișier obiect; în acest fel, dacă apare o eroare, este mai ușor să detectați ce fișier nu a reușit să compilați. Cu toate acestea, dacă tastați manual comenzile, există adesea multe fișiere specificate într-un singur apel gcc. Dacă poate apărea ambiguitate atunci când specificați mai multe fișiere pe linia de comandă, este mai bine să specificați un singur fișier. De exemplu, în loc de gcc -c -o a.o a.c b.c, este logic să folosiți gcc -c -o a.o b.c .
-D foo Definește macrocomenzile preprocesorului pe linia de comandă. Poate fi necesar să dezactivați caracterele care sunt tratate ca speciale de către shell. De exemplu, atunci când definiți un șir, ar trebui să evitați să utilizați caractere care se termină linia " . Iată cele două metode cel mai frecvent utilizate: "-Dfoo="bar"" și -Dfoo=\"bar\" . Prima metodă funcționează mult mai bine dacă există spații în șir, deoarece shell-ul tratează spațiile albe în mod diferit.
- Directorul I Adaugă un director la lista de directoare căutate după fișierele includ.
-L director Adaugă un director la lista de directoare în care sunt căutate bibliotecile gcc va favoriza bibliotecile partajate în detrimentul celor statice, dacă nu se specifică altfel;
- prostule Link-uri către biblioteca lib foo. Dacă nu este menționat altfel, gcc preferă conectarea cu biblioteci partajate (lib foo .so) decât cu cele statice (lib foo .a). Linker-ul caută în toate bibliotecile listate funcții în ordinea în care sunt listate. Căutarea se încheie când sunt găsite toate funcțiile necesare.
-static Link-uri doar cu biblioteci statice. Vezi capitolul 8.
-g , -ggdb Include informații de depanare. Opțiunea -g forțează gcc să includă informații standard de depanare. Opțiunea -ggdb indică necesitatea includerii unei cantități uriașe de informații doar depanator gdb.
Dacă spațiu pe disc limitat sau doriți să sacrificați unele funcționalități pentru viteza de conectare, ar trebui să utilizați -g . În acest caz, poate fi necesar să utilizați un alt depanator decât gdb. Pentru o depanare maximă, trebuie să specificați -ggdb . În acest caz, gcc va pregăti informații cât mai detaliate posibil pentru gdb. Trebuie remarcat faptul că, spre deosebire de majoritatea compilatoarelor, gcc pune câteva informații de depanare în codul optimizat. Cu toate acestea, urmărirea codului optimizat în depanator poate fi o provocare, deoarece execuția poate sări și să omite părți de cod care erau așteptate să fie executate. Cu toate acestea, vă poate oferi o idee bună despre modul în care compilatoarele de optimizare schimbă modul în care este executat codul.
-O , -O n Forțează gcc să optimizeze codul. În mod implicit, gcc efectuează o cantitate mică de optimizare; la specificarea numărului (n), optimizarea se realizează la un anumit nivel. Cel mai comun nivel de optimizare este 2; în prezent în versiunea standard a gcc cel mai mult nivel înalt optimizarea este 3. Vă recomandăm să utilizați -O2 sau -O3 ; -O3 poate crește dimensiunea aplicației, așa că dacă asta contează, încercați ambele opțiuni. Dacă memoria și spațiul pe disc sunt importante pentru aplicația dvs., puteți utiliza și opțiunea -Os, care minimizează dimensiunea codului cu prețul unui timp de execuție crescut. gcc activează încorporațiile numai atunci când se aplică cel puțin optimizarea minimă (-O).
-ansi Suport în programele C pentru toate standardele ANSI (X3.159-1989) sau echivalentul lor ISO (ISO/IEC 9899:1990) (denumit în mod obișnuit C89 sau mai puțin frecvent C90). Trebuie remarcat faptul că acest lucru nu asigură conformitatea deplină cu standardul ANSI/ISO.
Opțiunea -ansi dezactivează extensiile gcc care de obicei sunt în conflict cu standardele ANSI/ISO. (Deoarece aceste extensii sunt acceptate de multe alte compilatoare C, aceasta nu este o problemă în practică.) De asemenea, definește macro-ul __STRICT_ANSI__ (așa cum este descris mai târziu în această carte) pe care fișierele de antet o folosesc pentru a suporta un mediu compatibil ANSI/ISO.
-pedant Afișează toate mesajele de avertizare și de eroare cerute de standardul de limbaj ANSI/ISO C Acest lucru nu asigură conformitatea deplină cu standardul ANSI/ISO.
-Perete Permite generarea tuturor avertismentelor gcc, ceea ce este de obicei util. Dar în acest fel, opțiunile care pot fi utile în cazuri specifice nu sunt incluse. Verificatorul de sintaxă lint va oferi un nivel similar de granularitate cu codul sursă. gcc vă permite să activați sau să dezactivați manual fiecare avertisment de compilator; Manualul gcc explică toate avertismentele în detaliu.
5.2. Fișiere antet
5.2.1. lung lung

Tipul long long indică faptul că blocul de memorie este cel puțin la fel de mare ca lung . Pe Intel i86 și alte platforme pe 32 de biți, lung este de 32 de biți și lung este de 64 de biți. Pe platformele pe 64 de biți, pointerii și long long ocupă 64 de biți, iar long pot ocupa 32 sau 64 de biți, în funcție de platformă. Tipul lung lung este acceptat în standardul C99 (ISO/IEC 9899:1999) și este o extensie C de lungă durată furnizată de gcc.

5.2.2. Funcții încorporate

Unele părți ale fișierelor antet Linux (în special cele care sunt specifice sistemului) folosesc pe scară largă funcțiile încorporate. Sunt la fel de rapide ca macrocomenzi (fără supraîncărcare pentru apelurile de funcții) și oferă toate tipurile de verificare disponibile cu un apel de funcție normal. Codul care apelează funcții încorporate trebuie să fie compilat cu cel puțin optimizarea minimă (-O) activată.

5.2.3. Cuvinte cheie alternative extinse

În gcc, fiecare cuvânt cheie extins (cuvinte cheie care nu sunt definite de standardul ANSI/ISO) are două versiuni: însuși cuvânt cheieși un cuvânt cheie flancat pe ambele părți de două caractere de subliniere. Când compilatorul este utilizat în modul standard (de obicei când opțiunea -ansi este activată), cuvintele cheie extinse normale nu sunt recunoscute. Deci, de exemplu, cuvântul cheie cu atribut din fișierul antet ar trebui să fie scris ca __attribute__ .

5.2.4. Atribute

Cuvântul cheie cu atribut extins este folosit pentru a transmite mai multe informații despre o funcție, variabilă sau tip declarat către gcc decât permite codul ANSI/ISO C. De exemplu, atributul aliniat îi spune lui gcc cum să alinieze o variabilă sau un tip; atributul packed indică faptul că padding nu va fi folosit; noreturn specifică că o funcție nu va reveni niciodată, permițând gcc să optimizeze mai bine și să evite avertismentele false.

Atributele funcției sunt declarate prin adăugarea lor la declarația funcției, de exemplu:

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

O declarație de atribut este plasată între paranteze și punct și virgulă și conține cuvântul cheie atribut urmat de atributele din paranteze duble. Dacă există multe atribute, ar trebui utilizată o listă separată prin virgulă.

int printm(car*, ...)

Atribut__((const,

format(printf, 1, 2)));

Acest exemplu arată că printm nu ia în considerare alte valori decât cele specificate și nu are efecte secundare legate de generarea codului (const), printm indică faptul că gcc ar trebui să verifice argumentele funcției în același mod ca și argumentele printf(). Primul argument este șirul de format, iar al doilea este primul parametru de înlocuire (format).

Unele atribute vor fi acoperite pe măsură ce materialul progresează (de exemplu, în timpul discuției despre construirea bibliotecilor partajate din Capitolul 8). Informații cuprinzătoare despre atribute pot fi găsite în documentația gcc în format Texinfo.

Din când în când, s-ar putea să te trezești să răsfoiești titlurile. fișiere Linux. Probabil veți găsi o serie de modele care nu sunt conforme ANSI/ISO. Unele dintre ele merită înțelese. Toate constructele discutate în această carte sunt tratate mai detaliat în documentația gcc.

Din când în când, s-ar putea să te trezești că te uiți la fișierele de antet Linux. Probabil veți găsi o serie de modele care nu sunt conforme ANSI/ISO. Unele dintre ele merită înțelese. Toate constructele discutate în această carte sunt tratate mai detaliat în documentația gcc.

Secțiuni de pe această pagină:

Acum că știți ceva despre standardul C, să ne uităm la opțiunile pe care le oferă compilatorul gcc pentru a asigura conformitatea cu standardul C în limba pe care o scrieți. Există trei moduri de a vă asigura că codul dvs. C este compatibil cu standardele și nu prezintă defecte: opțiuni care controlează versiunea standardului la care intenționați să vă conformați, definiții care controlează fișierele de antet și opțiuni de avertizare care declanșează o verificare mai strictă a codului.

gcc are o gamă largă de opțiuni și aici le vom lua în considerare doar pe cele pe care le considerăm cele mai importante. O listă completă de opțiuni poate fi găsită în paginile de manual online gcc. De asemenea, vom discuta pe scurt câteva dintre opțiunile directivei #define care pot fi utilizate; De obicei, acestea ar trebui să fie specificate în codul sursă înaintea oricăror linii #include sau definite pe linia de comandă gcc. Ați putea fi surprins de câte opțiuni există pentru a selecta ce standard să utilizați, mai degrabă decât să bifați pur și simplu un semnalizare pentru a forța utilizarea standardului actual. Motivul este că multe programe mai vechi se bazează pe comportamentul istoric al compilatorului și ar necesita o muncă semnificativă pentru a le actualiza la cele mai recente standarde. Rareori, dacă vreodată, veți dori să vă actualizați compilatorul pentru a-l determina să rupă codul care rulează. Pe măsură ce standardele se schimbă, este important să puteți lucra împotriva unui anumit standard, chiar dacă acesta nu este cea mai recentă versiune a standardului.

Chiar dacă scrieți un program mic pentru uz personal, unde respectarea standardelor poate să nu fie atât de importantă, este adesea logic să includeți avertismente gcc suplimentare pentru a forța compilatorul să caute erori în codul dvs. înainte de a executa programul. Acest lucru este întotdeauna mai eficient decât executarea codului pas cu pas în depanator și întrebarea unde ar putea fi problema. Compilatorul are multe opțiuni care merg dincolo de simpla verificare a standardelor, cum ar fi capacitatea de a detecta codul care îndeplinește standardul, dar poate avea o semantică îndoielnică. De exemplu, un program poate avea un ordin de execuție care permite accesarea unei variabile înainte de a fi inițializată.

Dacă trebuie să scrieți un program pentru utilizare partajată, având în vedere gradul de conformitate cu standardul și tipurile de avertismente ale compilatorului pe care le considerați suficiente, este foarte important să depuneți puțin mai mult efort și să vă compilați codul fără avertismente la toate. Dacă lași să apară unele avertismente și iei obiceiul de a le ignora, într-o zi poate apărea un avertisment mai serios pe care riști să-l ratezi. Dacă codul dvs. se compila întotdeauna fără mesaje de avertizare, o nouă avertizare vă va atrage inevitabil atenția. Compilarea codului fără avertismente este un obicei bun de adoptat.

Opțiuni de compilare pentru urmărirea standardelor

Ansi este cea mai importantă opțiune de standarde și obligă compilatorul să acționeze conform standardului de limbaj ISO C90. Dezactivează unele extensii gcc care nu sunt conforme cu standardele, dezactivează comentariile în stil C++ (//) în programele C și permite gestionarea trigrafelor ANSI (secvențe cu trei caractere). În plus, conține macrocomanda __ STRICT_ANSI__, care dezactivează unele extensii din fișierele antet care nu sunt compatibile cu standardul. Standardul adoptat se poate modifica în versiunile ulterioare ale compilatorului.

Std= - Această opțiune oferă un control mai fin asupra standardului utilizat, oferind un parametru care specifică exact standardul necesar. Următoarele sunt principalele opțiuni posibile:

C89 - suportă standardul C89;

Iso9899:1999 - acceptă cea mai recentă versiune a standardului ISO, C90;

Gnu89 - Menține standardul C89, dar permite unele extensii GNU și unele funcționalități C99. În versiunea 4.2 a gcc, această opțiune este implicită.

Opțiuni pentru urmărirea standardului în directive defini

Există constante (#defines) care pot fi specificate ca opțiuni pe linia de comandă sau ca definiții în codul sursă al programului. În general, considerăm că acestea folosesc linia de comandă a compilatorului.

STRICT_ANSI__ - forțează utilizarea standardului ISO C. Determinat când opțiunea -ansi este dată pe linia de comandă a compilatorului.

POSIX_C_SOURCE=2 - Activează funcționalitatea definită în IEEE Std 1003.1 și 1003.2. Vom reveni la aceste standarde mai târziu în acest capitol.

BSD_SOURCE - Activează funcționalitatea sistemelor BSD. Dacă sunt în conflict cu definițiile POSIX, definițiile BSD au prioritate.

GNU_SOURCE - Permite o gamă largă de proprietăți și funcții, inclusiv extensii GNU. Dacă aceste definiții sunt în conflict cu definițiile POSIX, acestea din urmă au prioritate.

Opțiuni de compilare pentru ieșirea de avertizare

Aceste opțiuni sunt transmise compilatorului din linia de comandă. Din nou, le vom enumera doar pe cele principale, o listă completă poate fi găsită în manualul de referință online al gcc.

Pedantic este cea mai puternică opțiune pentru verificarea purității codului C Pe lângă activarea opțiunii de verificare standard C, dezactivează unele constructe C tradiționale interzise de standard și invalidează toate extensiile GNU la standard. Această opțiune ar trebui folosită pentru a maximiza portabilitatea codului dvs. C. Dezavantajul este că compilatorul este foarte preocupat de curățarea codului dvs. și, uneori, trebuie să vă grăbiți pentru a scăpa de puținele avertismente rămase.