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.

Declaraţii

Declaraţii

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:

Declaraţiile se folosesc pentru a specifica interpretarea pe care compilatorul trebuie să o dea fiecărui identificator.

Declaraţie:
specificator-declaraţie lista-declarator<opt>;
Specificator-declaraţie:
specificator-tip specificator-declaraţie<opt>
specificator-clasă-memorie specificator-declaraţie<opt>
Specificator-tip:
char
short
int
long
unsigned
float
double
void
specificator-structură-sau-reuniune
typedef-nume
Specificator-clasă-memorie:
auto
static
extern
register
const
typedef
Lista-declarator:
declarator-cu-iniţializare
declarator-cu-iniţializare, lista-declarator
Declarator-cu-iniţializare:
declarator iniţializator<opt>
Declarator:
identificator
(declarator)
* declarator
declarator ()
declarator [expresie-constantă<opt>]

Declaraţiile listează toate variabilele care urmează a fi folosite într-un program. O declaraţie specifică tipul, clasa de memorie şi eventual valorile iniţiale pentru una sau mai multe variabile de acelaşi tip. Declaraţiile se fac sau în afara oricărei funcţii sau la începutul unei funcţii înaintea oricărei instrucţiuni.
Nu orice declaraţie rezervă şi memorie pentru un anumit identificator, de aceea deosebim:
- declaraţia de definiţie a unei variabile, care se referă la locul unde este creată variabila şi unde i se alocă memorie;
- declaraţia de utilizare a unei variabile, care se referă la locul unde numele variabilei este declarat pentru a anunţa proprietăţile variabilei care urmează a fi folosită.

Specificatori de clasă de memorie

Specificatorii de clasă de memorie sînt:
auto static extern register
const typedef

Specificatorul typedef nu rezervă memorie şi este denumit „specificator de clasă de memorie” numai din motive sintactice; el va fi discutat în capitolul 10.
Semnificaţia diferitelor clase de memorie a fost discutată deja în paragraful 3.1.
Declaraţiile cu specificatorii auto, static şi register determină şi rezervarea unei zone de memorie corespunzătoare. Declaraţia cu specificatorul extern presupune o definiţie externă pentru identificatorii daţi, undeva în afara funcţiei sau fişierului în care ei sînt declaraţi.
Într-o declaraţie poate să apară cel mult un specificator de clasă de memorie. Dacă specificatorul de clasă lipseşte din declaraţie, el se consideră implicit auto în interiorul unei funcţii şi definiţie extern în afara funcţiei. Excepţie fac funcţiile care nu sînt niciodată automatice. De exemplu liniile:
int sp;
double val[MAXVAL];
care apar într-un program în afara oricărei funcţii, definesc variabilele externe sp de tip int şi val de tip masiv de double. Ele determină alocarea memoriei şi servesc de asemenea ca declaraţii ale acestor variabile în tot restul fişierului sursă. Pe de altă parte liniile:
extern int sp;
extern double val[];
declară pentru restul fişierului sursă că variabilele sp şi val sînt externe, sp este de tip int şi val este un masiv de double şi că ele au fost definite în altă parte, unde li s-a alocat şi memorie. Deci aceste declaraţii nu creează aceste variabile şi nici nu le alocă memorie.

Specificatori de tip

Specificatorii de tip sînt:
char short int long unsigned
float double void
specificator-structură-sau-reuniune
typedef-nume

Cuvintele long, short şi unsigned pot fi considerate şi ca adjective; următoarele combinaţii sînt acceptate:

short int
long int
unsigned int
unsigned long int
long double

Într-o declaraţie se admite cel mult un specificator de tip, cu excepţia combinaţiilor amintite mai sus. Dacă specificatorul de tip lipseşte din declaraţie, el se consideră implicit int.

Declaratori

Lista-declarator care apare într-o declaraţie este o succesiune de declaratori separaţi prin virgule, fiecare dintre ei putînd avea un iniţializator.
Declaratorii din lista-declarator sînt identificatorii care trebuie declaraţi.
Fiecare declarator este considerat ca o afirmaţie care, atunci cînd apare o construcţie de aceeaşi formă cu declaratorul, produce un obiect de tipul şi de clasa de memorie indicată. Fiecare declarator conţine un singur identificator. Gruparea declaratorilor este la fel ca şi la expresii.
Dacă declaratorul este un identificator simplu, atunci el are tipul indicat de specificatorul din declaraţie.
Un declarator între paranteze este tot un declarator, dar legătura declaratorilor complecşi poate fi alterată de paranteze.
Să considerăm acum o declaraţie de forma:
T D1
unde T este un specificator de tip (ca de exemplu int) şi D1 un declarator. Să presupunem că această declaraţie face ca identificatorul să aibă tipul „...T” unde „...” este vid dacă D1 este un identificator simplu (aşa cum tipul lui x în int x este int). Dacă D1 are forma:
*D
atunci tipul identificatorului pe care-l conţine acest declarator este „pointer la T”.
Dacă D1 are forma:
D()
atunci identificatorul pe care-l conţine are tipul „funcţie care returnează T”.
Dacă D1 are forma:
D[expresie-constantă] sau D[]
atunci identificatorul pe care-l conţine are tipul „masiv de T”.
În primul caz expresia constantă este o expresie a cărei valoare este determinabilă la compilare şi al cărei tip este int. Cînd mai mulţi identificatori „masiv de T” sînt adiacenţi, se creează un masiv multidimensional; expresiile constante care specifică marginile masivelor pot lipsi numai pentru primul membru din secvenţă. Această omisiune este utilă cînd masivul este extern şi definiţia reală care alocă memoria este în altă parte (vezi secţiunea 5.1). Prima expresie constantă poate lipsi de asemenea cînd declaratorul este urmat de iniţializare. În acest caz dimensiunea este calculată la compilare din numărul elementelor iniţiale furnizate.
Un masiv poate fi construit din obiecte de unul dintre tipurile de bază, din pointeri, din reuniuni sau structuri, sau din alte masive (pentru a genera un masiv multidimensional).
Nu toate posibilităţile admise de sintaxa de mai sus sînt permise. Restricţiile sînt următoarele: funcţiile nu pot returna masive, structuri, reuniuni sau funcţii, deşi ele pot returna pointeri la astfel de obiecte; nu există masive de funcţii, dar pot fi masive de pointeri la funcţii. De asemenea, o structură sau reuniune nu poate conţine o funcţie, dar ea poate conţine un pointer la funcţie. De exemplu, declaraţia
int i, *ip, f(), *fip(), (*pfi)();
declară un întreg i, un pointer ip la un întreg, o funcţie f care returnează un întreg, o funcţie fip care returnează un pointer la un întreg, un pointer pfi la o funcţie care returnează un întreg. Prezintă interes compararea ultimilor doi declaratori.
Construcţia *fip() este *(fip()), astfel că declaraţia sugerează apelul funcţiei fip şi apoi utilizînd indirectarea prin intermediul pointerului se obţine un întreg.
În declaratorul (*pfi)(), parantezele externe sînt necesare pentru arăta că indirectarea printr-un pointer la o funcţie furnizează o funcţie, care este apoi apelată; ea returnează un întreg.
Declaraţiile de variabile pot fi explicite sau implicite prin context. De exemplu declaraţiile:
int a,b,c;
char d, m[100];
specifică un tip şi o listă de variabile. Aici clasa de memorie nu este declarată explicit, ea se deduce din context. Dacă declaraţia este făcută în afara oricărei funcţii atunci clasa de memorie este extern; dacă declaraţia este făcută în interiorul unei funcţii atunci implicit clasa de memorie este auto.
Variabilele pot fi distribuite în declaraţii în orice mod; astfel listele le mai sus pot fi scrise şi sub forma:
int a;
int b;
int c;
char d;
char m[100];
Aceasta ultimă formă ocupă mai mult spaţiu dar este mai convenabilă pentru adăugarea unui comentariu pentru fiecare declaraţie sau pentru modificări ulterioare.

Modificatorul const

Valoarea unei variabile declarate cu acest modificator nu poate fi modificată.
Sintaxa:
const nume-variabilă = valoare ;
nume-funcţie (..., const tip *nume-variabilă, ...)
În prima variantă, modificatorul atribuie o valoare iniţială unei variabile care nu mai poate fi ulterior modificată de program. De exemplu,
const int virsta = 39;
Orice atribuire pentru variabila virsta va genera o eroare de compilare.
Atenţie! O variabilă declarată cu const poate fi indirect modificată prin intermediul unui pointer:
int *p = &virsta;
*p = 35;
În a doua variantă modificatorul const este folosit împreună cu un parametru pointer într-o listă de parametri ai unei funcţii. Funcţia nu poate modifica variabila pe care o indică pointerul:
int printf (const char *format, ...);

Iniţializare

Un declarator poate specifica o valoare iniţială pentru identificatorul care se declară. Iniţializatorul este precedat de semnul = şi constă dintr-o expresie sau o listă de valori incluse în acolade.

Iniţializator:
expresie
{listă-iniţializare}
Listă-iniţializare:
expresie
listă-iniţializare, listă-iniţializare
{listă-iniţializare}

Toate expresiile dintr-un iniţializator pentru variabile statice sau externe trebuie să fie expresii constante (vezi secţiunea 3.4) sau expresii care se reduc la adresa unei variabile declarate anterior, posibil offset-ul unei expresii constante. Variabilele de clasă auto sau register pot fi iniţializate cu expresii oarecare, nu neapărat expresii constante, care implică constante sau variabile declarate anterior sau chiar funcţii.
În absenţa iniţializării explicite, variabilele statice şi externe sînt iniţializate implicit cu valoarea 0. Variabilele auto şi register au valori iniţiale nedefinite (reziduale).
Pentru variabilele statice şi externe, iniţializarea se face o singură dată, în principiu înainte ca programul să înceapă să se execute.
Pentru variabilele auto şi register, iniţializarea este făcută la fiecare intrare în funcţie sau bloc.
Dacă un iniţializator se aplică unui „scalar” (un pointer sau un obiect de tip aritmetic) el constă dintr-o singură expresie, eventual în acolade. Valoarea iniţială a obiectului este luată din expresie; se efectuează aceleaşi operaţii ca în cazul atribuirii.
Pentru iniţializarea masivelor şi masivelor de pointeri vezi secţiunea 9.8. Pentru iniţializarea structurilor vezi secţiunea 10.3.
Dacă masivul sau structura conţine sub-masive sau sub-structuri regula de iniţializare se aplică recursiv la membrii masivului sau structuri.

Nume-tip

În cele expuse mai sus furnizarea unui nume-tip a fost necesar în două contexte:
- pentru a specifica conversii explicite de tip prin intermediul unui cast (vezi secţiunea 3.4);
- ca argument al lui sizeof (vezi secţiunea 4.2).
Un nume-tip este în esenţă o declaraţie pentru un obiect de acest tip, dar care omite numele obiectului.

Nume-tip:
specificator-tip declarator-abstract
Declarator-abstract:
vid
(declarator-abstract)
*declarator-abstract
declarator-abstract()
declarator-abstract[expresie-constantă<opt>]

Pentru a evita ambiguitatea, în construcţia:
(declarator-abstract)
declaratorul abstract se presupune a nu fi vid. Cu această restricţie, este posibil să identificăm în mod unic locul într-un declarator-abstract, unde ar putea apărea un identificator, dacă această construcţie a fost un declarator într-o declaraţie. Atunci tipul denumit este acelaşi ca şi tipul identificatorului ipotetic. De exemplu:
int
int*
int *[3]
int(*)[3]
int *( )
int(*)()
denumeşte respectiv tipurile int, „pointer la întreg”, „masiv de 3 pointeri la întregi”, „pointer la un masiv de 3 întregi”, „funcţie care returnează pointer la întreg” şi „pointer la o funcţie care returnează întreg”.
 
Top