Noi te platim pentru timpul acordat , o postare , like , vizualizare subiect , sau creare subiect , insemna castig.
Suntem comunitatea unica din Romania care plateste pentru efortul depus . Ideile ,opiniile tale conteaza si sunt platite doar la noi.

Liniile de control ale compilatorului

Liniile de control ale compilatorului

Solus

Membru
Staff member
Fondator BitArena
Moderator
Utilizator
Joined
Jul 6, 2018
Messages
523
Reaction score
94
Points
26
Location
Bucuresti
Website
www.bitarena.eu

Reputation:

Limbajul C oferă o facilitate de extensie a limbajului cu ajutorul unui preprocesor de macro-operaţii simple. Folosirea liniilor de forma:
#define
#include
este cea mai uzuală metodă pentru extensia limbajului, caracterul ’#’ (diez) indicînd faptul că aceste linii vor fi tratate de către preprocesor. Liniile precedate de caracterul ’#’ au o sintaxă independentă de restul limbajului şi pot apărea oriunde în fişierul sursă, avînd efect de la punctul de definiţie pînă la sfîrşitul fişierului.

Înlocuirea simbolurilor; substituţii macro

O definiţie de forma:
#define identificator şir-simboluri
determină ca preprocesorul să înlocuiască toate apariţiile ulterioare ale identificatorului cu şir-simboluri dat (şir-simboluri nu se termină cu ’;’ deoarece în urma substituţiei identificatorului cu acest şir ar apărea prea multe caractere ’;’).
Şir-simboluri sau textul de înlocuire este arbitrar. În mod normal el este tot restul liniei ce urmează după identificator. O definiţie însă poate fi continuată pe mai multe linii, introducînd ca ultim caracter în linia de continuat caracterul ’\’ (backslash).
Un identificator care este subiectul unei linii #define poate fi redefinit ulterior în program printr-o altă linie #define. În acest caz, prima definiţie are efect numai pînă la definiţia următoare. Substituţiile nu se realizează în cazul în care identificatorii sînt încadraţi între ghilimele. De exemplu fie definiţia:
#define ALFA 1
Oriunde va apărea în programul sursă identificatorul ALFA el va fi înlocuit cu constanta 1, cu excepţia unei situaţii de forma:
printf("ALFA");
în care se va tipări chiar textul ALFA şi nu constanta 1, deoarece identificatorul este încadrat între ghilimele.
Această facilitate este deosebit de valoroasă pentru definirea constantelor simbolice ca în:
#define TABSIZE 100
int tab[TABSIZE];
deoarece într-o eventuală modificare a dimensiunii tabelului tab se va modifica doar o singură linie în fişierul sursă. O linie de forma:
#define identif(identif-1,..., identif-n) şir-simboluri
în care nu există spaţiu între primul identificator şi caracterul ’(’ este o definiţie pentru o macro-operaţie cu argumente, în care textul de înlocuire (şir-simboluri) depinde de modul în care se apelează macro-ul respectiv. Ca un exemplu să definim o macro-operaţie numită max în felul următor:
#define max(a,b) ((a)>(b) ? (a) : (b))
atunci linia dintr-un program sursă:
x = max(p+q,r+s);
va fi înlocuită cu:
x = ((p+q)>(r+s) ? (p+q) : (r+s));
Această macro-definiţie furnizează o „funcţie maximum” care se expandează în cod, în loc să se realizeze un apel de funcţie. Acest macro va servi pentru orice tip de date, nefiind nevoie de diferite tipuri de funcţii maximum pentru diferite tipuri de date, aşa cum este necesar în cazul funcţiilor propriu-zise.
Dacă se examinează atent expandarea lui max se pot observa anumite probleme ce pot genera erori, şi anume: expresiile fiind evaluate de două ori, în cazul în care ele conţin operaţii ce generează efecte colaterale (apelurile de funcţii, operatorii de incrementare) se pot obţine rezultate total eronate.
De asemenea, trebuie avută mare grijă la folosirea parantezelor pentru a face sigură ordinea evaluării dorite. De exemplu macro-operaţia square(x) definită prin:
#define square(x) x*x
care se apelează în programul sursă sub forma:
z = square(z+1);
va produce un rezultat, altul decît cel scontat, datorită priorităţii mai mari a operatorului * faţă de cea a operatorului +.

Includerea fişierelor

O linie de forma:
#include "nume-fişier"
realizează înlocuirea liniei respective cu întregul conţinut al fişierului nume-fişier. Fişierul denumit este căutat în primul rînd în directorul fişierului sursă curent şi apoi într-o succesiune de locuri standard, cum ar fi biblioteca I/O standard asociată compilatorului. Alternativ, o linie de forma:
#include <nume-fişier>
caută fişierul nume-fişier numai în biblioteca standard şi nu în directorul fişierului sursă.
Deseori, o linie sau mai multe linii, de una sau ambele forme apar la începutul fiecărui fişier sursă pentru a include definiţii comune (prin declaraţii #define şi declaraţii externe pentru variabilele globale).
Facilitatea de includere a unor fişiere într-un text sursă este deosebit de utilă pentru gruparea declaraţiilor unui program mare. Ea va asigura faptul că toate fişierele sursă vor primi aceleaşi definiţii şi declaraţii de variabile, în felul acesta eliminîndu-se un tip particular de erori. Dacă se modifică un fişier inclus printr-o linie #include, toate fişierele care depind de el trebuie recompilate.

Compilarea condiţionată

O linie de control a compilatorului de forma:
#if expresie-constantă
verifică dacă expresia constantă este evaluată la o valoare diferită de zero.
O linie de control de forma:
#ifdef identificator
verifică dacă identificatorul a fost subiectul unei linii de control de forma #define.
O linie de control de forma:
#ifndef identificator
verifică dacă identificatorul este nedefinit în preprocesor.
Toate cele trei forme de linii de control precedente pot fi urmate de un număr arbitrar de linii care, eventual, pot să conţină o linie de control forma:
#else
şi apoi de o linie de control de forma:
#endif
Dacă condiţia supusă verificării este adevărată, atunci orice linie între #else şi #endif este ignorată. Dacă condiţia este falsă atunci toate liniile între testul de verificare şi un #else sau în lipsa unui #else pînă la #endif sînt ignorate.
Toate aceste construcţii pot fi imbricate.

Utilizarea dirctivelor de compilare

Prezentăm în continuare un exemplu didactic de utilizare a directivelor de compilare în dezvoltarea unor proiecte.
Se citeşte de la tastatură o pereche de numere naturale p şi q. Să se determine dacă fiecare din cele două numere este prim sau nu, şi să se calculeze cel mai mare divizor comun.
Să rezolvăm această problemă folosind două fişiere sursă. Primul conţine funcţia main şi apelează două funcţii: eprim şi cmmdc. Al doilea fiţier implementează cele două funcţii.
Prezentăm mai întîi un fişier header (numere.h) care conţine definiţiile celor două funcţii.

#ifndef _Numere_H
#define _Numere_H
unsigned eprim(unsigned n);
unsigned cmmdc(unsigned p, unsigned q);
#endif

Fişierul sursă princ.c este foarte scurt.

#include <stdio.h>
#include "numere.h"
static void citire(unsigned *n) {
scanf("%u",n);
if (eprim(*n))
printf("%u e prim\n",*n);
else
printf("%u nu e prim\n",*n);
}
int main() {
unsigned p,q,k;
citire(&p);
citire(&q);
k=cmmdc(p,q);
printf("Cmmdc: %u\n",k);
return 0;
}

Fişierul sursă numere.c este prezentat în continuare.

#include "numere.h"
unsigned eprim(unsigned n) {
unsigned i,a,r;
if (n==0) return 0;
if (n<4) return 1;
if ((n&1)==0) return 0;
for (i=3; ; i+=2) {
r=n%i;
if (r==0) return 0;
a=n/i;
if (a<=i) return 1;
}
}
unsigned cmmdc(unsigned p, unsigned q) {
while ((p>0) && (q>0))
if (p>q) p%=q;
else q%=p;
if (p==0) return q;
else return p;
}

Pentru a obţine un program executabil din aceste două fişiere se poate utiliza o singură comandă de compilare:
Cc princ.c numere.c opţiuni-de-compilare
unde Cc este numele compilatorului folosit (exemplu: bcc, gcc). Opţiunile de compilare (atunci cînd sînt necesare) sînt specifice mediului de programare folosit.

Proiectele – programe de dimensiuni mari – sînt compuse de cele mai multe ori din module care se elaborează şi se pun la punct separat. Uneori pot fi identificate funcţii care prezintă un interes general mai mare, şi care pot fi utilizate în elaborarea unor tipuri de aplicaţii foarte diverse. Acestea sînt dezvoltate separat şi, după ce au fost puse la punct în totalitate, se depun într-o bibliotecă de funcţii în format obiect. În momentul în care acestea sînt incluse în proiecte nu se mai pierde timp cu compilarea modulelor sursă. În schimb modulele care le apelează au nevoie de modul cum sînt descrise aceste funcţii, şi acesta se păstrează în fişiere header.
 
Top