CATEGORII DOCUMENTE |
Manual de referinta C
1. Introducere
Acest manual descrie limbajul C implementat pe PDP-11,
Honeywele 6000, IBM System370 si Interdata 832. In
blocurile unde exista diferente (intre implemntari) el se
refera la PDP-11, dar se incearca punctarea detaliilor
dependente de implementare. Cu mici diferente, aceste
dependente sint legate direct de proprietatile hardware (ale
masinilor); diverselel compilatoare sint in general compatibile.
2. Conventii lexicale
Exista sase clase de simboluri: identificatori, cuvinte-cheie,
constante, (in mod colectiv numite 'spatii albe')asa cum vor fi
descrise in continuare. sint ignorate cu exceptia cazurilor cind
servesc la repararea simbolurilor. Unele spatii albe sint necesare
pentru a separa identificatori adiacenti, cuvint-cheie si
constante.
Daca sirul de intrare (pentru compilator) a fost analizat (si
transformat) in simboluri pina la un caracter dat, urmatorul
simbol va include cel mai lung sir de caractere care poate
constitui un simbol.
2. 1. Comentarii
Caracterele /* incep un comentariu, care se termina cu
caracterele*/. Comentariile nu pot fi imbricate.
2. 2 Identificatori (nume)
Un identificator este o secventa de litere si cifre;primul
caracter trebuie sa fie litera. Sublinierea (underscor) este
considerata litera literele mari si mici sint diferite. dDoar
primele 8 caractere sint semnificative, desi pot fi folosite mai
multe. Identificatorii externi care sint utilizati de o serie de
asamblare sau incarcatoare, sint mai restrictivi:
PDP-II 7 caractere, 2cazuri, casete (cases)
Homywele 6000 6caractere, 1caset.
IBM 360/370 7caractere, 1case
Interdata 8/32 8caractere, 2 cases
2. 3. Cuvinte cheie
Urmatorii idenntificatori sint rezervati pentru a fi folositi
ca si cuvinte cheie, si nu pot fi folositi altfel:
int extern else
char register for
float typedef do
double static while
struct goto switch
union return case
long sizeof default
short break entry
unsigned continue
auto if
Cuvintul cheie 'entry' nu este implementat de nici un
compilator, dar este rezervat pentru o utilizare ulterioara. Unele
implementari rezerva si cuvintele 'fortran' si 'asm'
2. 4. Constante
Exista o serie de contante decrise in continuare.
Caracteristicile hardware care afecteaza dimensiunile sint
rezumate in $2.
2. 4. 1. Constante intregi
O constanta intreaga constind dintr-o serie de cifre va fi
considerata in octal daca incepe cu 0 (cifra zero), astfel va fi
considerata in zecimal. O secvanta de cifre precedata de ox
sau OX (cifra zero) este considearata intreg hexazecimal.
Daca valoarea unei constante zecimale depaseste posibilitatile
hardware de inmagazinare a intregilor ea va fi considerata
de tip 'long'. Acelsi lucru se intimpla si pentru constantele
octale sau hexazecimale.
2. 4. 2. Constantelungi explicite
O constanta intreaga de tip octal, zecimal sau hexazecimal urmata
de caracterul 'l'sau'L' este considerata consatnta lunga. Dupa
cum va fi discutat la unele masini intregii si valorile 'long' pot
fi considerate identice.
2. 4. 3. Constante tip caracter
O constanta tip carcter este un caracter intre ghilimele simple
cum ar fi de exemplu '*'. Valoarea unei constante tip
caracter este valorea numerica a caracterului corepunzator
setului de caractere al masinii. Unele caractere negrafice,
cum sint ghilimeaua si backspace pot fi reprezentate dupa
cum urmeaza, conform unei tabele de secvente 'escape'.
newline NL(LP) n
horisontaltab HT t
backspace BS b
carriagereturn CR r
formfeed FF f
backslash
ghilimea ' '
modelbinar ddd ddd 'bit pattern'
Secventa ddd consta din caracterul backslash uramt de 1, 1 sau 3
cifre octale care vor specifica valorea unui caracter dorit. Un
caz special de constructie este 0 (neurmat de nici o cifra) care
indica un caracter NULL. Daca caracterul care urmeaza dupa nu
este de tipul specificat, se ignora .
2. 4. 4. Constante in virgula mobila
O constanta in virgula mobila consta dintr-o parte intreaga,
punct zecimal parte fractionara un 'e' sau 'E' si optional s un
intreg cu semn pe post de exponent.
Intregul si partea fractionara pot fi o secvente de cifre. Atit
intregul cit si partea fractionara (dar nu simultan ) pot lipsi;
si punctul zecimal sau 'e' si exponentul (nu simultan) pot
lipsi. Constantele sint in dubla precizie reprezentate.
2. 5. Siruri
Un sir este o secventa de caractere intre ghilimele duble, de
exemplu '' Un sir este de tipul 'tabloul de caractere ' si
in clase de memorare 'static' (vezi &4) si se initializeaza cu
caracterele date. Toate sirurile, chiar daca sint scrise identic,
sint distincte. Compi latorul plaseaza caracterul 0 (byte nul)
la sfirsitul fiecarui sir astfel ca programele care pot detecta
sfirsitul sirului. Intr-un sir, car acterul ' trebuie precedat de
; in plus, secventele deschise pentru constante tip caracter pot
fi folosite. In sfirsit , un si un NL care urmeaza imediat sint
ignorate.
2. 6. Caracteristici hardware
Tabelul care urmeaza rezuma unele proprietati de hardware care
variaza de la masina la masina. Acestea afecteaza
portabilitatea programeleor; in practica aceasta este o problema
care trebuie privita aprioric.
DEC PDP11 HONEYWELL IBM370 INTERDATA8/32
ASCII ASCII EBCDIC ASCII
char 8biti 9 8 8
int 16 36 32 32
short 16 36 16 16
long 32 36 32 32
float 32 36 32 32
double 64 72 64 64
gama reprez. I10-38 I10-38 I10-76 I10-76
+ + +
Pentru aceste patru tipuri de masina, numerele in VF au exponentul
de 8 biti.
3. Notatii sintactice
In manual notatiile sintactice sint scrise cu tipul italic
de caracter cuvintele literale sint caractere tipul drept.
Categoriile alternative sint listate pe linii separate. Un
simbol optional terminal sau nonterminal este indicat prin
subscrierea 'opt', astfel: indica o expresie
optionala intre acolade. Sintaxa este rezumata in $18.
4. Ce este un nume ?
C-ul isi bazeaza interpretarea unui identificator de doua
atribute ale identificatorului: 'clasa de memorare ' si 'tipul'.
Clasa de memorare determina locatia si durata de viata a
unei celule de memorare asociate unui identificator; tipul
determina semnificatia valorii depuse in celula de memorare
a identificatorululilL.
Exista patru clase de memorare declarabile: automatic,
staticexterna si tip registru. Variabilele automatice sint locale
fiecarei apelari a unui bloc (vezi $9. 2) si sint declasate la
iesirea din blocul respectiv. Variabilele statice sint locale unui
bloc, dar retin valoarea pina la revenirea in blocul respecitv
chiar daca controlul a parasit blocul; variabilele exxterne exista
si pastreaza valoarealor in decursul executiei intregului
program si pot sa fie folosite pentru comunicare intre functii
chiar funcctii compilate separat. Variabilele de tip registru
sint numerotate (daca este posibil) in registrii rapizi ai
masinii, ca si variabilele automate sint locale blocului si
dispar la iesirea din bloc.
C suporta citeva tipuri fundamentale de obiecte:
Obiectele declarate ca si caractere (char) sint sufiecient de
mari pentru a sufoca orice membru a setului de caractere
ale implementarii, si daca un caracter pur din acest set de
caractere este sufocat intr-o variabila de tip caracter, valoarea
sa este echivalenta cu codul intreg pentru acel caracter (cu
valoarea intregului care reprezinta caracterul in reprezentarea
interna (NI)) Si alte cantitati pot fi sufocate in variabile tip
caracter, dar implementarea este dependenta de masina.
Sint disponibile 3 dimensiuni de intregi declarati short int, int
si long int. Intregii lungi permit starii mai mari decit cei
scurti, dar implementarea poate face ca intregii scurti, sau
cei lungi, sau ambii sa devina echivalenti cu intregii de baza.
Acestia au dimensiunea naturala decurgind din arhitectura
masinii, celelalte tipuri sint prevazute pentru cerinte speciale.
Intregii fara semn, declarati unsigned se supun legilor
aritmeticii modulo 2n unde n este numarul de bitdin
reprezentare. (La PDP11 cantitatile lungi fara semn nu sint
suportate)
Cantitati in VF simpla (float) sau dubla (double) pot sa fie
sinonime in unele implementari.
Pentru ca cantitatile descrise pot fi interpretate ca numere ce
sint referite ca fiind de tip 'aritmetic'. Tipurile char si int
de toate dimensiunile vor fi in mod colectiv numite de tip
'intreg'. (float si double vor fi denumite de tip 'flotant'.
In afara tipurilor aritmetice de baza exista, conceptual, o clasa
infinita de tipuri derivate din tipurile de baza in modul
urmator:
-tablouri de obiecte de multe tipuri
-functii care dau obiecte de un tip dat
-pointeri la obiecte de un tip dat
-structuri constituind o secvnta de obiecte de tipuri
variate
-marimi capabile sa contina oricare unitate de obiecte de
tipuri varaibie
In general aceste metode de constructie a obiectelor pot fi
aplicate recursiv.
5. Obiecte si lvalori
Un obiect este o regiune manipulabila de memorare; o LVALOARE
este o expresie referitoare la un obiect. Un ex simplu de
expresie LVALOARE este un identificator. Exista operatori
care creaza (produc) lvalori: de ex, daca E este o expresie de
tipul pointer, atunci *E este o expresie lvaloare
referitoare la obiectul spre care pointeaza E. Numele
'lvaloare' vine de la expresia de asignare E1=E2 in care operandul
sting E1 trebuie sa fie o expresie 'lvaloare'. Discutarea, mai
jos, a fiecarui operator indica cind se asteapta operanzi
'lvaloare ' si cind operatorul produce o 'lvaloare'.
6. Conversii
Un numar de operatori depinzind de operanzii lor sa cauzeze
conversia unei valori a operandului dintr-un tip in altul. Aceasta
sectiune explica rezultatul care se asteapta in urma unei
astfel de conversii; &6. 6 rezuma conversiile cerute de
majoritatea operatiilor curente (ordinare N. T) tabloul va
fi imbogatit dupa (prin) discutarea fiecarui operator.
6. 1. Caractere si intregi
Un caracter sau un intreg scurt pot fi folosite oriunde un
intreg se poate folosi. In toate cazurile valoarea este
convertita intr-un intreg. Conversia unui intreg scurt intr-unul
lung implica o extensie de semn; intregii sint cantitati cu
semn. Extensia de semn pt caractere depinde de masina, dar se
garanteaza ca un membru al unui set de caractere standard este ne-
negativ. Dintre masinile discutate aici dar la PDP-11 se extinde
semnul. La PDP-11 valoarea variabilelor tip caracter este in
gama -128 la +127; caracterele alfabetului ASCII sint
toate pozitive. O constanta tip caracter specificata octal sufera
o extensie de semn si poate apare negativa de exemplu '377' are
valoarea -1.
Cind un intreg mai lung este convertit intr-unul mai scurt sau
char el este trunchiat la stinga; bitii in exces sint deplasati
(pierduti).
6. 2. Float si double
Toata aritmetica in C este realizata in dubla precizie; cind
apare un float intr-o expresie el este 'lungit' (extins) in
double prin introducere de zeroruri in partea sa fractionara.
Cind un double este convertit in float, de exemplu printr-o
asignare, double-ul este rotunjit inaintea de trunchiere pe
lungimea unui float.
6. 3. Flotante si intregi
Conversia unei valori flotante in tip intreg devine dependenta
de masina in particular directia de trunchiere a numerelor
negative variaza de la masina la masina. Rezultatul este
nedefibnit daca valoarea nu incape in spatiul prevazut (N. T. pt
un intreg). Conversiile din intreg in flotant sint realizate bine.
Poate apare o pierdere a preciziei daca detinatia nu are un numar
suficient de biti.
6. 4. Pointeri si intreg
Un intreg sau un intreg lung poate fi adunat sau scazut dintr-
un pointer; in acest caz primul este convertit asa cum se
specifica la operatia de adunare. Doi pointeri la obiecte de
acelasi tip pot fi scazuti; in acest caz rezultatul este convertit
intr-un intreg asa cum se va discuta la operatia de scadere.
6. 5. Fara semn
Oridecite ori un intreg fara semn si un intreg normal (de
baza tipic) sint combinati, intregul tip este convertit in intreg
fara semn si rezultatul va fi fara semn. Valoarea este cel mai
mic intreg fara semn congruent intregului cu semn ( modulo2 si
lungimea caracterului). In reprezentarea in complement fata de 2,
conversia este conceptuala si nu se modifica tabloul
(distributia) bitilor. Cind un intreg fara semn este
convertit in long , valoarea rezultatului este aceasi
numeric, ca si a intregului fara semn. Deci conversia este
introducere de zerouri spre stinga.
6. 6. Conversii aritmetice
Multi operatori cauzeaza conversii si produc rezultate de un
tip oarecare, intr-un mod similar. Acest model va fi numit
'conversii aritmetice uzuale'. Intii, oricare operand de tipul
char sau short va fi convertit in int, iar oricare operand de
tipul float este convertit in tipul double.
Apoi, daca un operand este de tip double, atunci si celalalt este
convertit in double si acesta va fi tipul rezultatului. Astfel
daca un operand este long, celalalt este convertit in long si
acesta va fi tipul rezultatului. Astfel, daca un operand este
unsigned, celalalt este convertit in unsigned si acesta va fi
tipul rezultatului. Astfel, daca ambii operanzi sint int, acesta
va fi tipul rezultatului.
7. Expresii
Precedenta (prioritatea ) operatorilor din expresii este
aceasi cu ordinea subsectiunilor din aceasta sectiune,
priritatea maxima fiind prima daca de exemplu expresiile referite
ca operatori pentru +(&74) sint expresiile defiite in &&7. 1-7.
3. In fiecare subsectiune operatorii au aceeasi precedeta.
Asociativitatea la stinga sau la dreapta este specificata in
fiecare din operatorii din operatorii discutati in cadrul
subsectiunii. Precedenta si asociativitatea tuturor operatorilor
din expresii este rezumata in gramatica din &18.
Astfel ordinea de evaluare a expresiilor este nedefinita.
In particular compilatorul se considera liber de a calcula
subexpresiile de maniera pe care el o considera cea mai
eficienta, chiar daca subexpresiile pot conduce la efecte
secundare. Ordinea de aparatie a efectelor secundare este
nespecificata. Expresiile care contin un comutator comutaiv si
asociativ (*, +, &, |, ^) pot fi rearanjate arbitrar, chiar in
prezenta parantezelor, pentru a se forta ordine particulara de
evaluare o explicitare temporara devine necesara.
Prelucrarea depasirilor superioare si verficarea impartirilor
la evaluarea expresiilor este dependenta de masina. Toate
implementarile C-ului ignora depasirile superioare intregi;
prelucrarea impartirii cu 0, si toate exceptiile VF variaza intre
masini si sint uzual ajustabile printr-o functie de biblioteca.
7. 1 Expresii primare
Expresiile primare care contin., ->, subscrieri, si apeluri
de functii se grupeaza de la stinga la dreapta.
primary-expresion:
identifier
constant
string
(expresion)
primary-expresion[expresion]
primary-expresion(expresion-list opt)
primary-lvalue. identifier
primary-expresion->identifier
expresion-list:
expresion
expresion-list, expresion
Un idetificator este o expresie primara, cu garantia ca a fost
declarat asa cum se va discuta. Tipul sau este
specificat la declarare. Daca tipul idetificatorului este
'tablouri de' atunci valoarea expresiei
identificatorului sau este un pointer la primul obiect din
tablou, iar tipul expresiei este 'pointer la'. Mai mult, un
idetificator de tablou (masiv) nu este o lvaloare. La fel un
idetificator care e declarat 'function returning' (functie
care returneaza ), cind este folosit (cu exceptia cazului cind
apare ca numele functiei la un apel) este convertit in
'pointer la functia ce returneaza'.
O constanta este o expresie primara. Tipul ei poate fi int,
long sau double, depinzind de forma sa. Constantele tip
caracter au tipul int; constantele flotante sint double.
Un sir este o expresie primara. Tipul sau original (la origine)
este 'tablou de char'; urmind insa aceeasi regula data
pentru identificatori, acesta este modificat in 'pointeri catre
char' si rezultatul este un pointer catre primul caracter al
sirului (exista o exceptie pt unele initializari a se vedea
&8.6.).
O exprsie in paranteze este expresie primara a carui tip si
valoare sint identice cu ale expresiei fara paranteze.
Prezenta parantezelor nu are implicari daca expresia este o
lvaloare. O expresie primara urmata de o expresie in
paranteze drepte este o expresie primara. Sensul intuitiv este
acela al unui indice. Obisnuit expresia primara are tipul
'pointer catre', expresia indicelui este int, iar tipul
rezultatului este '' (!!! N. T. ). Expresia E1[E2] este
identica (prin definitie) cu *((E1)+(E2)). Toate reguluile
necesare intielegerii acesteinotatii sint continute in
aceasta sectiune impreuna cu discutiile din &&7. 1, 7. 2 si 7.
4. asupra identificatorilor, *, si respectiv +; &14. 3 rezuma
implicatiile.
Un apel de functie este expresie primara urmata de
paranteze continid un posibil vid, o lista de expresii separate
prin virgule constituind argumentele actuale ale functiei.
EXpresia primara trebuie sa fie de tipul 'functie care
returneaza', si rezultatul apelului functiei este de tipul
''. Cum se va indica, un identificator nevazut urmat de o
paranteza stinga este contextual declarat ca reprezentind o
functie care returneaza un intreg; deci in majoritatea
cazurilor functiile car dau ca rezultat o valore intreaga nu
trebuie declarate.
Orice argument actual de tipul float este convertit in double
inainte de apel; oricare argument de tipul char sau short
este convertit in int; si, ca deobiecei numele de tablouri
sint convertit in pointere. Daca este necesara o conversie se va
folosi (N. T. cast) vezi &7. 2, 8. 7.
La pregatirea unui
apel la o functie se face o copie a fiecarui parametru actual
adica toate trecerile de argumente in C se fac prin valoare. O
functie poate modifica valorea parametrilor sai formali, dar
aceste modificari nu acteaza valoarea parametrilor actuali !Mai
mult se poate trece un pointer cu subintelesul functia poate
modifica valoarea obiectului spre care pointerul indica. Un
nume de tablou este o expresie pointer. Ordinea de evaluare a
argumentelor este nedefinita de catre limbaj;a se nota ca
difera de la compiler la compiler. Sint permise apeluri recursive
la orice functie. O expresie primara urmata de un punct
urmat de un identificator este o expresie. Prima expresie
trebuie sa fie o lvaloare un signed a structurii sau o reuniune
iar identificatorul trebuie sa fie un membru a structurii
sau reuniunii. Rezultatul este o lvaloare referind membrul numit
al structurii sau reuniunii.
O expresie primara urmata de o sageata (care se construieste din
-si >) urmata de un identificator este oexpresie. Prima expresie
trebuie sa fie un pointer la o structura sau la o reuniune si
identificatorul trebuie sa numeasca un membru al acelei
structuri sau reuniuni. Rezultatul este lvaloare care
refereaza membrul numit al structurii sau reuniunii catre
care pointerul expresiei puncteaza.
Astfel <expresia E1->MOS este identica cu (*E1). MOS. Structurile
si reuniunile se discuta in &8. 5. Regulile date aici pentru
utilizarea structurilor si reuniunilor nu nu sint stricte, de
maniera care permite sa se scape de mecanismul tipurilor. Vezi
&14.1.
7. 2. Operatori unari
Expresiile cu operatori unari se grupeaza de la dreapta la stinga.
unary-expression:
*expression
&lvalue
-expression
!expression
-expression
++lvalue
--lvalue
lvalue++
lvalue--
(type-name)expression
sizeof expression
sizeof(type-name)
Operatorul * inseamna indirect: expresia trebuie sa fie un
pointer si rezultatul este o lvaloare care se refera la
obiectul spre care pointeaza expresia. Daca tipul unei expresii
este 'pointer catre' tipul rezultatului este ''.
Rezultatul operatiei & este un pointer catre obiectul referit
prin lvaloare. Daca tipul lvalorii este ' ' tipul rezultatului
este 'pointer catre'.
Rezultatul unei operatii este negarea operandului. Se
realizeaza conversiile aritmetice obisnuite. Negativul unei
cantitati este calculat prin scaderea valorii sale din 2 la n
, unde 'n' este nr de biti pe care se reprezinta un int. Nu exista
operatorul unar +.
Rezultatul operatiei de negare logica ! este 1 daca valorea
operandului a fost 0, si 0 daca operandul este non-zero. Tipul
rezultatului este int. Operatia este aplicabila oricarui tip de
opernand aritmetic sau pointerilor.
Obiectul referit prin operandul lvaloare precedat de ++ este
incrementat. Valoarea este noua valoare a operandului dar nu
este o lvaloare. Expresia ++x este echivalenta cu x+=1. A se vedea
adunarea (&7. 4) si operatorii de asignare (&7. 14) pentru
informatii asupra conversiilor.
Operandul lvalorii cu prefixul -- este decrementat analog cu ++.
Cind postfixul ++ este aplicat unei lvalori rezultatul este
valorea obiectului referit pr in lvaloarea. Dupa ce
rezultatul este notat obiectul este incrementat in
aceeasi maniera ca pentru operatorul prefix++. Tipul
rezultatului este acelasi cu tipul expresiei lvaloare.
Cind postfixul -- este aplicat unei lvalori rezultatul este
valoarea obiectului referit prin lvaloare. Dupa notarea
rezultatului obiectul este decrementat in maniera prefixului --.
Tipul rezultatului este acelasi cu tipul expresiei lvaloare.
O expresie precedata de un nume de tip de data in paranteze
cauzeaza conversia valorii expresiei in tipul de data numit
constructia este denumita un cast (rol distributie, ). Numele
de tipuri de date sint descrise in &8. 7.
Operatorul sizeof produce marimea in bytes a opeandului sau. (Un
byte nu este definit de limbaj decit in termenul de valore a
lui sizeof). Dar in toate implementarile un byte este spatiul
necesar pastrarii unui char. Aplicat unui tablou rezultatul este
numarul total de bytes din tablou. Marimea se determina din
declaratiile obiectelor in expresii. Expresia este semnatic o
constanta intreaga si poate fi folosita oriunde este necesara o
constanta. Se foloseste la comunicarile cu subprograme ca
alocatori de memorie si sisteme de //0.
Operatorul sizeof poate fi aplicat unui nume de tip de data in
paranteze. In acest caz va da marimea in bytes, a unui obiect de
tipul indicat.
Constructia sizeof (type) este 1 deci expresia sizeof(type) -2
este aceeasi cu (sizeof(type)) -2.
7. 3. Operatori de inmultire
Operatorii de inmultire *, /, % grupeaza de la stinga la dreapta.
Se realizeaza conversiile aritmetice uzuale.
multiplicative-expression:
expression*expression
expression/expression
expression%expression
Operatorul binar* indica inmultire. Operatorul * este asociativ
si expresiile cu mai multe inmultiri de acelasi nivel pot fi
rearanjate de compilator.
Operatorul /indica impartire. Cind se impart intregi
pozitivi se face o trunchiere spre 0, dar forma trunchierii
este dependenta de masina daca unul din operanzi este negativ.
Pe toate masinile discutate in acest manual restul are semnul
impartitorului. Todeauna este adevarat ca (a/b) *b+a%b este egal
cu a (daca b e diferit de zero).
Operatorul % produce restul impartirii primei expresii la a doua.
Se realizeaza conversiile aritmetice uzuale. Operanzii trebuie sa
nu fie float.
7. 4. Operatori aditivi
Operatorii aditivi + si- grupeaza de la stinga la dreapta.
Se realizeaza conversiile aritmetice uzuale. Exista citeva
posibilitati de tip aditionale pentru fiecare operator.
aditive-expression:
expression+expression
expression-expression
Rezultatul operatiei + este suma operanzilor. Un pointer
catre un obiect dintr-un tablou si o valare de orice tip intreg
pot fi adunate. Ultima este in toate cazurile convertita intr-un
deplasament de adresa (N. T. address offset) prin inmultirea cu
lungimea obiectului spre care indica pointerul. Rezultatul este
un pointer de acelasi tip cu pointerul original si care indica
un alt obiect din acelasi tablou, corespunzator deplasat fata
de obiectul original. Deci daca P este un pointer catre un
pointer dintr-un tablou (N. T. array) expresia P+1 este un pointer
catre urmatorul element (obiect) din tablou.
Nu este permisa o alta forma de combinatie de tipuri pentru pointeri.
Operatorul + este asociativ si expresiile cu adunari multiple la
acelasi nivel pot fi rearanjate de compiler. Rezultatul
operatorului - este difernta dintre operanzi. Se realizeaza
conversi aritmetice uzuale. In plus o valore de orice tip de
intreg poate fi scazuta dintr-un pointer cu aceeasi conversie ca
la adunare.
Daca doi pointeri catre obicte de acelasi tablou sint scazuti
rezultatul este convertit (prin impartire cu lungimea
obiectlui) intr-un int care reprezinta numarul de obicte care
separa obictele indicate (pointed-to). Conversia poate da
rezultate neasteptate, daca pointerii nu indica oectele
aceluiasi tablou intrucit pointerii chiar spre obiecte de
acelasi tip nu difera printr-un multiplu al lungimii obiectelor.
7. 5. Operatori de deplasare
Operatorii de deplasare << si >> grupeaza stinga la
dreapta. Ambii fac conversiile uzuale asupra operanzilor fiecare
trebuind sa fie un intreg. Apoi operandul din dreapta se
cponverteste in int; tipul rezultatului este aceea al operandului
din stinga. Rezultatul este nedefinit daca operandul din dreapta
este negativ sau > sau = cu lungimea obiectului in biti.
shift-expression:
expression<<expression
expression>>expression
Valoarea lui E1<<E2 este E1 (interpretat ca forma de biti)
deplasat la stinga; biti eliminati sint umpluti cu zero.
Valoarea lui E1>>E2 este E1 deplasat dreapta cu E2 pozitii
binare. Deplasarea la dreapta este garantat a fi logica (cu
umplere de zerouri) daca E1 nu are semn; altfel poate fi (si este
la PDP11) aritmetica (cu umplerea bitului semn).
7. 6. Operatori relationali
Operatorii relationali grupeaza stinga la dreapta dar acest fapt
nu este foarte folositor; a<b<c nu inseamna ceea ce pare.
relational-expression:
expression<expression
expression>expression
expression<=expression
expression>=expression
Operatorii <, >, <=, >= dau 0 daca relatia este falsa si 1 daca
este adevarata. Tipul rezultatului este int. Se fac
conversiile uzuale. Doi pointeri se pot compara rezultatul
depinde de locatiile relative in spatiul de adrese a
obiectelor poinate. Comparatia pointerilor este portabila numai
cind pointerii indica spre obiecte din acelasi tablou.
7. 7. Operatori de egalitate
equality-expression:
expression==expression
expression!=expression
Semnul == (egal cu) si !=(inegal cu ) sint analogi operatorilor
relationali dar nu au prioritate mai mica. (adica a<b==c<d
este 1 daca a<b si c<d au valoare adevarat).
Un pointer poate fi comparat cu un intreg dar rezultatul va fi
dependent de masina. Cu exceptia cazului cind intregul este
constanta 0. Un pointer caruia i s-a asigurat valorea 0 se
garanteaza ca nu va pointa spre nici un obiect si va apare a fi
egal cu 0;in utilizarea conventionala un astfel de pointer este
considerat nul.
7. 8. Operatorii si pe biti:
and expression:
expression&expresion
operatorul & este asociativ si expresiile continind & pot fi
rearanjate Se realizeaza conversiile aritmetice uzuale; rezultatul
este functia SI pe biti, a celor doi operanzi. Operatorul se
aplica numai operanzilor intregi.
7. 9. Operatorul sau exclusiv pe biti
exclusive-or-expression:
expression^expression
Operatorul ^ este asociativ si expresiile care contin ^ pot fi
rearanjate. Se realizeaza conversiile aritmetice uzuale;
rezultatul este SAU exclusiv al celor doi operanzi la nivel de
bit. Operatorul se aplica doar operanzilor intregi.
7. 10 Operatorul sau inclusiv
inclusiv-or-expression:
expression|expression
Operatorul | este asociativ expresiile care-l contin pot fi
rearanjate. Se realizeaza conversii aritmetice uzuale; rezultatul
este functie SAU inclusiv a operanzilor la nivel de bit.
Operatorul se aplica doar operanzilor intregi.
7. 11. Operatorul si logic
logical-and-expression:
expression&&expression
Operatorul && grupeaza de la stinga la dreapta. El da 1 daca
ambii operanzi sint diferiti de 0 altfel da 0. Nu ca &, &&
garanteaza o evaluare de la stinga la dreapta; al doilea operand
nu este evaluat daca primul este egal cu 0.
Operanzii pot fi de tipuri diferite dar fiecare trebuie sa
fie unul din tipurile fundamentale sau un pointer. Rezultatul este
intodeauna int.
7. 12 Operatorul sau logic
logical-or-expression:
expression||expression
Operatorul || opereaza de la stinga la dreapta. El da 1 daca unul
din operanzi este diferit de 0 si altfel da 0. Nu ca |, ||
face evaluare la stinga -> dreapta, al doilea operand nu mai este
evaluat daca primul este diferit de 0.
Operanzii pot fi de tipuri diferite dar de tipurile de baza
(fundamentale) sau pointeri. Rezultatul este totdeauna int.
7. 13 Operator conditional
conditional-expression:
expression?expression:expression
opereaza de la dreaptspre stinga. Prima expresie este evaluata si
daca este non zero rezultatul este valoarea celei de a doua
expresii. Altfel este al celei dea treia expresii. Daca este
posibil conversiile artimetice uzuale se fac pentru a aduce a
doua si a treia expresie la un tip comun; se poate ca unul sa fie
pointer si celalat zero, si rezultatul are tipul
pointerului. Numai expresiile a doua si a treia sint evaluate.
7. 14. Operatori de atribuire
Operatorii de atribuire opereaza de la dreapta spre stinga.
Toate solicita o lvaloare ca opernd stinga, iar tipul unei
expesii de asigurare este acela al operandului din stinga.
Valoarea este valoarea stocata in operandul din stinga dupa ce
asigurarea s-a facut. Cele doua parti ale unui operator de
asigurare compus sint elemente sintactice (atomi)separati.
assignement-expression:
lvalue=expression
lvalue+=expression
lvalue-=expression
lvalue*=expression
lvalue/=expression
lvalue%=expression
lvalue>>=expression
lvalue<<=expression
lvalue&=expression
lvalue^=expression
lvalue|=expression
La asigurarea simpla cu = valoarea expresiei inlocuieste pe cea a
obiectului referit prin lvaloare. Daca ambii operanzi sint de
tip aritmetic operandul drept se converteste in tipul celui sting
inainte de asigurare.
Comportarea unei expresii dforma E1op=E2 poate fi inferred luind
ca echivalent al ei E1=E1op(E2); oricum E1 este evaluata doar
odata. La += si -= operandul sting poate fi un poninter in
care opernadul din dreapta (intreg) este convertit dupa cum
se explica in &7. 4; toti opernazii din dreapta si toti opernazii
stingi non pointeri trebuie sa fie de tip aritmetic.
Compilatoarele permit ca un pointer sa fie asignat unui intreg,
un intreg sa fie asignat unui pointer si un pointer sa fie asignat
unui pointer de alt tip. Asignarea este operatia de copiere pura
fara conversii. Aceasta utilizare este neportabila si poate
produce pointeri care pot cauza exceptii de adresare la utilizare.
Este garantata asignarea constantei zero la un pointer aceasta
producind un pointer nul distinct de orice pointer spre orice
obiect.
7. 15 Operatorul virgula
comunn-expression:
expression, expression
O pereche de expresii separate prin virgula este evaluata de
la stinga la dreapta si valorea expresiei din stinga este
declasata. Tipul si valoarea rezultatului sint tipul si
valorea operandului din dreapta. Operatorul lucreaza de la
stinga la dreapta. In contextul unde virgulei i se da un inteles
special, de exemplu intr-o lista de argumente pt o fc. (&7. 1)
sau liste de initializare (&8. 6), operatorul - virgula
descrisa aici poate apare doar in paranteze, de exemplu:
f(a, (t=3, t+2), c)
are trei argumente, al doilea avind valoarea 5.
CAPITOLUL 8. Declaratii
Declaratiile sint folosite pt a specifica interpretarea pe care C
o da fiecarui identificator; nu fac in mod necesar si
rezervarea de memorie pt respectivul identificator. Declaratiile
au forma:
declaration:
decl-specifiers declarator-list opt;
Declaratorii din lista de declaratori contin identificatorii
de declarat. Specificatorii de declaratii constituie o secventa
de specificatori de tip si clase de memorare:
decl-specifiers:
type-specifier decl-specifiers opt
sc-specifier decl-specifiers opt
lista trebuie sa fie unica (self consistent) in exemplul
descris mai jos. (N.T. -sc=storage class)
8. 1. Specificatori de clase de memorare
Acestia sint:
sc-specifier:
auto
static
extern
register
typedef
specificatorul 'typedef' nu rezerva memorie si este numit
'specificator' de clasa de memorie ' doar din motive
sintactice; se diacuta la &8. 8 sensurile diverselor claselor de
memorare s-au discutat in &4.
Declaratiile auto, static si register servesc ca definitii pt
ca cauzeaza o rezervare de memorie. La extern trebuie sa existe o
definire externa (vezi &10) pt identificatori dati undeva in afara
functiei unde ei au fost declarati.
Declaratia register este mai des vazuta ca o declaratie auto
impreuna cu o alertare a compilatorului ca aceste varaibile vor fi
utilizate des. Doar citeva declaratii de acest tip sint
efective. Mai mult doar varaibilele de anumite tipuri vor fi
stocate in registre; la PDP11 acestea sint int, char si pointeri.
O alta restrictie se refera la variabilele registru.
Operatorul & (care lucreaza cu adrese) nu li se poate aplica
programele create pot deveni mai mici mai rapide dintr-o utilizare
de declaratii register folosite corespunzator, dar inbunatatiri
viitoare lae generarii de cod pot sa le faca necesare.
Cel putin un specificator de tip memorare poate fi dat intr-o
declarare. Daca lipseste el este considerat auto in interiorul
functiei, si extern in afara ei. Exceptie: functiile nu sint
niciodata automatic.
8. 2. Specificatori de tip
type-specifier:
char
short
int
long
unsigned
float
double
struct-or-union-specifier
typedef-name.
Cuvintele long, short si unsigned pot fi privite ca si
adjective; urmatoarele combinatii sint aceptabile.
short int
long int
unsigned int
long float
Sensul ultimei constructii este acelasi cu double. Altfel
cel mult un specificator de tip poate fi dat intr-o declaratie.
Daca specificatorul de tip lipseste el este considerat int.
Specificatorii de structuri si reuniuni vor fi discutati in &8. 5,
declaratiile cu typedef sint discutate in &8. 8.
8. 3. Declaratori
Lista de declaratori care apare intr-o declaratie este o secventa
separata prin virgula de declaratori, fiecare trebuind sa aiba o
initializare.
declarator-list:
init-declarator
init-declarator, declarator-list
int-declarator:
declarator initialiser opt.
Initializatorii sint discutati in &8. 6. Specificatorii dintr-
o declarattie indica tipuri si clase de memorare a
obiectelor la care se refera declaratorii. Declaratorii au
sintaxa:
declarator:
identifier
(declarator)
*declarator
declarator()
declarator[constant-expression opt]
Gruparea este ca la expresii.
8. 4. Sensul declarartorilor
Fiecare declarator este o afirmatie de genul ca atunci cind o
constructie de aceeasi forma ca si declaratorul apare intr-o
expresie, va produce un obiect de tipul si clasa indicata. Fiecare
declarator contine doar un identificator;acest identificator se
declara.
Daca doar un identificator apare ca declarator, atunci el va avea
tipul indicat de specificatorul de la inceputul declaratiei.
Un declarator in paranteze este identic cu un declarator fara
atribute, dar amestecarea declaratorilor complecsi poate fi
alterat prin paranteze. Vezi exemplele de declaratie.
Acum sa ne imaginam o declaratie
T D1
unde T este un specificator de tip (ca int) si D1 este un
declarator. Sa presupunem ca aceasta declaratie face ca
identificatorul (N. T. din declarator) sa aibe tipul ''unde '
' este gol daca D1 este doar un identificator pur si sipmplu (asa
ca tipul lui X din 'int X' este doar int ). Daca D1 are forma:
*D
tipul identificatorului continut este 'pointer la T'.
Daca D1 are forma
D()
atunci identificatorul continut are tipul ' functie ce
returneaza T. '
Daca D1 are forma D[constant-expression] sau D[], atunci
identificatorul continut are tipul 'tablou de T'. In primul
caz expresia constantei este o expresie a carei valoare este
determinabila in momentul compilarii si care are tipul int
(expresiile
multe specificatii de tsblou sint adiacente se creaza un
tablou multidimensional; expresiile constanta care specifica
limitele tablourilor pot sa lipseasca doar pentru primul membru al
secventei. Aceasta forama este folositoare daca tabloul e extern
si definitia actuala, care aloca spatiu, este totusi data.
Prima expresie contanta poate fi omisa daca declaratorul
este urmat de o initializare. In acest caz marimea se
calculeaza din nr elemente precizate.
Un tablou poate fi constituit din unul din tipurile de baza
prin pointeri dintr-o structura sau reuniune, sau din alt
tablou (pt a genera tablouri cu dimensiuni multiple).
Nu toate posibilitatile date de sintaxa sint permise.
Restrictiile sint urmatoarele: functiile nu pot returna tablouri,
structuri sau reuniuni dar pot returna pointeri spre asa ce va;
nu exista tablouri de functii dar pot exista tablouri de pointeri
spre functii. O structura sau o reuniune nu poate contine o
functie, dar poate contine un pointer la o functie. Exemple:
int i; *ip, f(), *fip(), (*pfi)();
decalara
un intreg i
un pointer ip la un intreg
o functie f care returneza un intreg
o functie fip care returneaza un pointer la un intreg
un pointer pfi la o functie care reurneaza un intreg
Se compara ultimele. *fip() este *(fip()) declaratia
sugereaza si aceiasi constructie intr-o expresie necesita apelul
functiei fip si apoi indirectarea spre rezultat (pointer) se
produce un intreg. (*pfi)() in declaratie parantezele sint
necesare ca si intr-o expresie ca sa indice ca indirectarea prin
pointeri la o functie produce o functie care este apoi chemata; va
returna un intreg.
Alt exemplu:
float fa[17], *afp[17]
declara un tablou de flotante si un tablou de pointere spre numere
flotante.
In final:
static int x3d[3][5][7];
declara un tablou de intregi, static, cu dimensiunile 3x5x7.
In detaliu X3d este un tablou de 3 articole; fiecare articol este
un tablou de 5 tablouri; si fiecare din ultimul este un tablou
de 7 intregi. Oricare din expresiile x3d, x3d[i], x3d[i][j],
x3d[i][j][k] poate apare intr-o expresie. Primele trei sint de tip
'tablou', ultima are tipul int.
8. 5. Declaratorii de structuri si reuniuni
O structura este un obiect constind dintr-o secventa de
memorii cu nume. Fiecare membru poate avea orice tip. O
reuniune este un obiect care, la un moment dat, poate contine pe
oricare din mai multi membri.
Specificatorii de structuri si reuniuni au aceeasi forma:
struct-or-union-specifier:
struct-or-union
struct-or-union identifier
union identifier
declara identificatorul ca eticheta (marcaj) de structura
(sau uniune) a structturii specificate de lista. O declaratie de a
treia forma
struct identifier
union identifier
Etichetele de structura permit definirea de structuri auto-
referibile ele permit ca partea lunga a unei structuri sa fie
data odata si folosita de mai multe ori. Este ilegal a declara
o structura sau uniune care face apel la ea insasi, dar o
structura sau uniune poate contine un pointer la un apel spre ea
insasi.
Numele membrilor si etichetele sint la fel ca pentru variabilele
ordinare dar sa fie distincte mutual.
Doua structuri pot folosi in comun o secventa initiala de membri;
adica acelasi membru apare in doua structuri diferite daca au
acelasi tip in ambele si daca membrii anteriori sint acesasi
in ambele(In momentul de fata, compilatorul verfica numai daca
in unul din doua structuri diferite are acelasi tip si
deplasament in ambele, dar daca membrii precedenti difera,
constructtia este neportabila ).
Exemplu simplu de declarare de structura:
struct tnode;
contine
-un tablou de 20 caractere
-un intreg
-2 pointeri catre structuri similare
Odata aceasta declaratie facuta, declaratia
struct tnode s, *sp;
declara S ca fiind o structura de tipul dat si sp un pointer
la o structura de tipul dat.
Cu aceste declaratii expresia:
sp->count
Se refera la cimpul count spre care pointeaza sp;
s. left
Se refera la pointerul subarborelui stinga
s. right->tword[0]
Se refera la primul caracter al subarborelui tword din arborelui
drept al lui S.
8. 6. Initializare
Un declarator poate specifica o valoare initiala pt
identificatorul declarat. Initializatorul este precedat de = si
consta dintr-o expresie sau o lista de valori in acolade.
initializer:
=expression
=
=
initializer-list:
expression
initializer-list, initializer-list
Toate expresiile pentru initializarea unei variabile statice
sau externe trebuie sa fie expresii de
&15, sau expresii care se reduc la adresa variabilei declarate
anterior, cu posibilitatea de a fi deplasate printr-o
initializate cu expresii arbitrare care pot contine
constante, variabile declarate anterior si functii.
Variabilele statice si externe neinitializate la start primesc
valoarea zero. Cele automatic si register au continut nespecificat
(probabil 'gunoi').
Cind intr-un initializator se aplica unui scalar (pointer sau un
obiect de tip aritmetic) el consta din expresie singulara
posibil in paranteze. Valoarea initiala a obiectului se obtine
din expresie; aceleasi conversii ca pentru atribuire se folosesc.
Cind o variabila declarata este un agregat ( structura sau
tablou) atunci initializatorul consta dintr-o lista de
initailizatori separati prin virgule in parantze (acolade) scri
si in dinea in care cresc indicii sau in orinea membrilor.
Daca numarul de initializatori este mai mic decit al membrilor
se impune restul cu 0. Nu se initializeaza uniuni sau agregate de
tip automatic.
Acoladele se pot elimina. Daca un initilizator incepe cu acolade
stinga atunci va urma o lista de initializare cu
initializatori despartiti stinga prin virgule pentru membrii
agregatului; este eronat sa existe mai multi initializatori
decit membri. Daca initializatorul nu incepe cu acolada stinga
atunci se iau din lista numarul necesar de elemente pentru
agregatul curent, restul lasati la dispozitia agrgatului urmator.
De exemplu:
int x[]=;
x este declarat si initializat cu un tablou cu o dimensiune
care are trei membri.
float y[4][3]={
, initializeaza prima linie adica y(0)
, care este y[0][0], y[0][1] si y[0, 2]
, apoi se initializeaza liniile y[1] si y[2]
}; y[3] se inittializeaza cu 0.
Acelasi efect se obtine cu:
float y[4][3]=;
Initializarea pentru y incepe cu acolada stinga, dar pentru y[0]
nu, de ci se folosesc trei elemente din lista. Urmatorele trei
sint luate pentru y[1] si y[2]. Deci:
float y[4][3]=, , ,
};
initializeaza prima coloana a lui y (privit ca un tablou cu
doua dimensiuni) si lasa restul pe zero.
Si:
char msg[]='syntax error on line %s/n';
arata un tablou de caractere a carui membri sint initializati cu
un sir.
8. 7. Nume de tipuri
In doua contexte (pt a se specifica explicit o expresie cu
ajutorul unei distributii (N. T. cast) si ca si argument pt
size of) este de dorit a se specifica numele unui tip de data.
Aceasta se realizeaza folosind 'nume de tip' care este in
esenta o declaratie pt un obiect de tipul respectiv care omite
numele obiectului.
type-name:
type-specifier abstract-declarator.
abstract-declarator:
empty
(abstract-declarator)
*abstract-declarator
abstract-declarator()
abstract-declarator[constant-expression opt]
Pentru a se evita ambiguitatea in constructia
(abstract-declarator),
abstract-declaratorul nu trebuie sa fie vid. Cu aceasta
restrictie se poate identifica unic locatia din abstract-
declarator unde va apare declaratorul daca constructia a fost un
declarator intr-o declaratie. Tipul de nume este acelasi cu tipul
unui identificator ipotetic de exemplu:
int tip->intreg
int* pointer la (catre) intreg
int*[3] tablou de 3 pointeri la intregi
int(*)[3] pointer la un tablou format din 3 intregi
int*() functie care returneaza un pointer la un intreg
int(*)() pointer la o functie care returneaza un intreg
8. 8. Typedef
Declaratiile a caror 'clasa de memorare' este typedef nu definesc
o memorie ci definesc identificatori care vor fi utilizati
ulterior ca si cum ar fi cuvinte cheie de tip denumind tipuri
fundamentale sau derivate.
typedef-name:
identifier
Rorul unei declaratii continind typedef este ca orice
identificator care apare ca parte a oricarui declarator din
interiorul (declaratiei) devine sintactic echivalenta cu cuvintele
cheie de tip numind cuvintele de tip asociat identificatorului in
modul desis in &8..De exemplu, dupa:
typedef int MILES, *KLICKSP;
typedef structcomplex;
Constructiile
MILES distance;
extern KLICKSP metricp;
complex 2, *zp;
sint declaratii legale; tipul lui distance este int, al lui
metricp este 'pointer la un int', si al lui z este structura
specificata; zp este pointer la respectiva structura.
typedef nu introduce tipuri noi, numai sinonime pt tipuri care se
pot specifica si altfel. In exemplul distance este considerat
a avea exact acelasi tip ca orice alt obiect int.
9. Enunturi
Cu exceptiile ce vor fi indicate, enunturile se executa in
secventa.
9. 1. Enunt expresie
Multe enunturi sint enunturi expresie, care au forma:
expression;
In general enunturile expresie sint asignari sau apeluri de
functie.
9. 2. Enuntul compus sau block
Se prevede enuntul compus intrucit se pot folosi mai multe
enunturi acolo unde este asteptat doar unul:
compound-statement;
declaration-list:
declaration
declaration, declaration-list
statement-list
statement
statement statement-list
Daca unul din identificatorii din lista de declaratii a fost
declarat anterior, declaratia externa este decazuta pentru
durata unui bloc, dupa care isi epuizeaza forta.
Orice initializare de variabile auto sau register se realizeaza de
fiecare data cind se intra in bloc la virful sau. Este posibil(
dar este o practica rea ) de a face transferul in bloc; in acest
caz nu se face initializarea.
Initializarea variabilelor static se face doar odata, la
inceputul executiei programului. In bloc, declaratiile extern
nu rezerva memorie astfel ca initializarea nu este permisa.
9. 3. Enunturi conditionale
Sint 2 forme de enunturi conditionale:
if(expresie) statement
if(expresie) statement else statement
In ambele cazuri se evalueaza expresia si daca nu sint zero se
executa primul enunt. In al 2-lea caz se executa a 2-a
instructie daca prima este egala cu zero. Ambiguitatea lui
'else' este rezolvata prin conectarea unui 'else' cu ultimul
'else-less if' intilnit.
9. 4. Instructii while
Forma: while(expression)statement
Instructia din while este executat repetat atita timp cit
valoarea expreie ramine diferita de zero. Testul se face inainte
de executia instructiei.
9. 5. Instructia do
Are forma
do statement while(expression);
Instructia este executata repetat pina cind valorea expresiei
devine zero. Testul se face dupa fiecare executie a instructiei.
9. 6. Instructia for
Are forma:
for(expression-1opt;expression-2opt;expression-3opt)statement
Este echivalenta cu:
expression-1;
while(expression-2)
Deci prima expresie specifica initializarea buclei; a doua
specifica un test, facut inaintea fiecarei iteratii, astfel ca
din bucla se iese cind expresia devine zero; a 3-a expresie
specifica o incrementare care este realizata dupa fiecare
iteratie.
Oricare sau toate expresiile pot lipsi. Daca lipseste a doua
instructie while implicata devine echivalenta cu while(1);
celelalte expresii vor lipsi din constructia data.
9. 7. Instructia switch
Instructia switch face ca controlul sa fie transferat la una
din mai multe instructii functie de valoarea expresiei. Are forma:
switch(expression)statement
Se executa conversiile necesare, dar rezultatul trebuie sa fie
int. Instructia este compusa. Orice instructie din bloc pate
fi etichetata cu un prefix tip case
case constant-expression
unde expresia de constanta va fi un intreg(int). Este interzisa
aparitia a doua constante pentru case in aceasi instructie
switch cu aceeasi valoare. Constantele se definesc precis in
&4. 5.
Poate exista un prefix de instructie de forma
default:
Cind se executa instructia switch, expresia se evalueaza si
se compara cu constantele case. Daca una este egala cu valorea
expresiei, controlul se va da la instructia urmind prefixul gasit.
Daca nu exista instructii cu case-ul cautat, dar exista
prefixul defaault, controlul se da la instructia prefixata.
In lipsa prefixului default nu se executa nici una din
instructiuni.
case si default, in sine, nu altereaza mersul programului.
Iesirea din switch se face cu break (vezi &9. 8) In general
instructia al carui subiect este switch este un bloc.
Declaratii pot apare la inceputul instructiei, dar
initializarea variabilelor automatic si register sint
inefective.
9. 8. Instructia break
Are forma: break; si face sa se termine ciclul cel mai intern
while, do, for sau switch. Controlul trece la instructia care
urmeaza dupa instrucctia de terminare.
9. 9 Instructia continue
Are forma:
continue;
si face sa se treaca la continuarea in bucla a celui mai intern
while, do sau for; adica se sare la sfirsitul buclei. Mai precis,
in fiecare din instructiile
while() do }while(); }
O instrcutie continue este echivalenta cu goto contin(Dupa contin:
o instructie goala)
9. 10. Instructia return
O functie revine la apelant cu instructia return care are formele:
return;
return expression;
In primul caz valoarea returnata nu e definita. In al doilea
caz valoarea expresiei este returnata apelantului. Daca se cere,
expresia este cnvertita, ca la asignare, in timpul functiei in
care apare. Ocolirea finalului unei functii este echivalenta cu
nereturnarea de valoare la apelant.
9. 11. Instructia goto
Controlul se poate transfera neconditionat cu ajutorul instructiei:
goto identifier;
Identificatorul trebuie sa fie o eticheta (vezi 9. 12) din functia
curenta.
9. 12 Instructii etichetate
Oricare instructie poate fi precedata de un prefix eticheta de
forma
identifier:
care serveste pentru declararea identificatorului ca si
eticheta. Unica utilizare a etichetei este de tinta a unui
goto. Bataia unei etichete este functia curenta, excluzind sub
blocurile in care acelasi identificator poate fi redeclarat. Vezi
&11.
9. 13 Instructia nula
Are forma
;
Este folosita pentru ca poate purta o eticheta chiar inainte de
}(N. T. acolada finala) a unei instructii compuse sau servind ca
si corp de instructii nul unei instructii de buclare gen while.
10. Definitii externe
Un program C consta dintr-o secventa de definitii externe. O
definitie externa declara un identificator ca avind clasa de
memorare extern (in lipsa specificatorului sau static,
si un tip specificatn tip specificat. Specificatorul de tip
(vezi 8. 2) poate fi vid, in care caz tipul va fi luat ca si int.
Intinderea unei definitii externe persista pina la sfirsitul
fisierului in care a fost declarata asa cum efectul unei
declaratii persista pina la sfirsitul unui bloc. Sintaxa
defintiilor extern este aceeasi ca a tuturor declaratorilor, cu
exceptia ca numai la acest nivel poate fi dat codul pentru
functii.
10. 1. definitii defunctie externe
Definitiile de functii au forma:
function-definition:
decl-specifiersopt function-declarator function-body
Singurii specificatori de clasa de memorare permisa in cadrul
specificatorilor de declaratii sint extern sau static; a se
vedea &11. 2 pentru distinctia dintre ele. Un declarator de
functie este similar cu un declarator pentru 'functie care
returneaza' cu exceptia ca el listeaza parametrii formali ai
functiei de definit.
function-declarator:
declarator(parameter-listopt)
parameter-list:
identifier
identifier, parameter-list
Corpul functiei are forma:
function-body:
declaration-list compound-statement
Identificatorii din lista de parametrii, si numai acesti
identificatori, pot fi declarati in lista de declaratii. Orice
identificator al carui tip nu este dat se considera a fi de tip
int. Singurul tip de clasa de memorare care poate fi specificata
este register; daca aceasta e specificata, parametrul actual
corespunzator va fi copiat, daca este posibil, intr- un
registru in codul codului functiei. Un exemplu simplu de definitie
completa de functie este:
int max(a, b, c)
int a, b, c;
Aici int este specificator de tip;max(a, b, c) este declaratorul
de functie int a, b, c; este lista de declaratii pentru
parametrii formali; este blocul care da codul pentru
instructie.
'C'converteste parametrii actuali de tip float in double, astfel
ca parametrii formali declarati float isi vor avea declaratiile
ajustate pentru a se citi double. Astfel, daca o referinta la
un tablou in orice context (in particular cu un parametru
actual)este cnsiderata a avea sensul unui pointer la primul
element al unui tablou, declaratiileparametrilor formali de
genul 'tablou de' sint ajustate in 'pointeri catre'. In
final, intrucit structurile, uniunile si functiile nu pot fi
trecute unei functii, este fara utilizare declararea ca parametri
formali a unei structuri, uniuni sau functii (pointerii la astfel
de obiecte sint permisi).
10. 2. Definitii de date externe
O definitie de data externa are forma:
data definition:
declaration
Clasa de memorare a unei astfel de date poate fi extern (in
lipsa) sau static dar nu auto sau register.
11. Reguli despre domenii
Un program in C poate sa nu fie compilat tot deodata:
textul sursa al progarmului poate fi pastrat in mai multe fisiere
si rutine precompilate pot fi incaracte din biblioteci.
Comunicatiile intre functiile unui program pot fi apeluri
explicite sau utilitare de date externe.
Exista 2 feluri: primul, ce ar putea fi numit obiectivul
lexical al unui identificator, care este in esenta regiunea
unui program in timpul caruia el poate fi folosit fara a apare
eroarea de 'identificator nedefinit'; si al 2-lea obiectivul
asociat cu identificatori externi care se caracterizeaza prin
regula ca referinta la acelasi identificator extern sint referinte
la acelasi obiect.
11. 1 Domeniu lexical
Obiectivul lexical al identificatorilor declarati in
definitiile externe se intinde de la definitie pina la
sfirsitul fisierului sursa in care apare. Intinderea lexicala a
indentificatorilor care sint parametri formali persista in functia
cu care sint asociati. Scopul lexical al identificatorilor
declarati la inceput de bloc tine pina la sfirsitul
blocului. Intentia lexicala a etichetelor este in functia in care
apar.
Intrucit toate referintele la acelasi identificator extern se
refera la acelasi obiect(vezi 11. 2)compilatorul verifica
toate declaratiile aceluiasi identificator extern pt
compatibilitate; de fapt puterea lor se intinde asupra intregului
fisier pe care apar.
In toate cazurile, daca un identificator este explicit declarat
la inceputul unui bloc, incluzind blocul care constitue o
functie, orice declaratie al acelui identificator in afara
blocului este suspendata pina la sfirsitul bocului.
De reamintit (vezi 8. 5) ca identificatorii asociati cu
varaibile ordinare pe de o parte si acei asociati cu membrii
ai unor structuri sau reuniuni pe de alta parte, frmeaza doua
clase disjuncte fara conflict intre ele. Membrii (de reuniuni sau
structuri n. t. ) si etichetele urmeaza aceleasi reguli obiectuale
ca si identificatorii; numele declarate cu typedef sint de
aceasi clasa cu identificatorii ordinari. Ei pot fi redeclarati
in blocurile interne, dar un tip explicit se va da in declaratia
interioara.
typedef float distance;
De notat ca f trebuie declarata explicit in rutina apelanta pt
ca aparitia sa in g(f) nu este urmata de (.
14. 3. Tablouri, pointeri si indici
De fiecare data cind un identificator de tipul tablou apare intr-
o expresie el este convertit intr-un pointer catre primul
element al tabloului. Din cauza acestei conversii tablourile nu
sint lavlori. Prin definitie operatorul indice [] este
interpretat de asa maniera incit E1[E2] e identic cu *((E1)+(E2)).
Din cauza regulilor de conversie care se aplica lui +, daca E1
este tablou si E2 intreg atunci E1(E2) se refera la al E2-
lea membru al lui E1. Darin ciuda acestei aparente asimetrii,
indicii formeaza o operatie comutativa.
O regula soloida se aplica in cazul tablourilor
multidimensionale. Daca E este un tablou de ordinul 'n' si
indici ixjxxk atunci cind E apare intr-o expresie el va fi
convertit intr-un pointer la un tablou cu 'n-1' dimensiuni cu
indici jxxk. Daca se aplica operatorul *, explicit sau
implicit ca rezultat al utilizarii indicilor, rezultatul este un
tablou pointat de n-1 dimensiuni, care este imediat convertit
intr-un pointer. De exemplu:
int x[3][5];
Unde x este un tablou de intregi cu 3X5 elemente. Cind x apare
intr-o expresie, este convertit intr-un pointer catre(primul
din cele 3) tabloul de 5 membrii intregi. In expresia x[i],
care e echivalenta cu *(x+i), X este mai intii convertit intr-
un pointer asa cum s-a descris;i este apoi convertit in tipul
lui x, care implica inmultirea lui i cu lungimea
obiectului spre care pointeaza, adica 5 obiecte intregi.
Rezultatul se aduna si se aplica indirectarea producind
un tablou(de intregi) care este la rindul sau transformat
intr-un pointer la primul dintre intregi. Daca mai este un indice
acelasi procedeu se aplica din nou; acum rezultatul va fi un
intreg.
Rezulta ca in C tablourile sint stocate pe linii (ultimul
indice variaza cel mai repede ) si ca primul indice din
declaratie permite sa se de termine necesarul de memorie dar nu
are alt rol in calculul indicilor.
14. 4. Conversii de pointeri explicite
Unele conversii de pointeri sint permise doar au aspecte
dependente de implementare. Toate se specificaprin conversii
explicite de tip ca in &7. 2 si &8. 7.
Un pointer se poate converti in oricare tip de intreg suficient
de mare pentru a-l pastra. Dar a utiliza int sau long este
dependent de masina. Functiile de mapare sint dependente de, dar
nu vor surprinde pe aceea care cunosc structura de adresare a
masinii. Detalii se dau mai jos.
Un obiect de tip intreg poate fi convertit explicit in pointeri.
Maparea face ca un intreg convertit din pointer sa dea acelasi
pointer, depinzind de masina. Un pointer catre un tip poate
fi convertit intr-un pointer la alt tip. Pointerul rezultat
da exceptii de adresare la folosire daca pointerul subiect nu se
refera la un obiect aliniat corespunzator in memorie. Se
garanteaza ca un pointer la un obiect de o marime data poate fi
convertit intr-un pointer catre un obiect mai mic in dimensiune si
inapoi fara modificari.
De exemplu, rutina de alocare de memorie poate accepta o
marime (in biti, a unui obiect de alocat si sa returneze un
pointer char; acesta putind fi folosit conform scopului.
extern char *alloc();
double *dp;
dp=(double*)alloc(sizeof(double));
*dp=22. 0/7. 0;
alloc trebuie sa asigure (de o maniera dependenta de masina)
ca valoarea pe care o returneaza este corespunzatoare connversiei
intr-un pointer catre double < atunci utilizarea functiei este
portabila.
Reprezentarea pointerului la PDP-11 este un intreg de 16 biti si
se masoara in bytes; chars nu necesita aliniere speciala;
orice altceva trebuie sa aiba o adresa para.
Pe Honeywell un pointer are 36 de biti si e intreg; adresa de
cuvint e pe cei 18 biti din stinga, iar bitii care selecteaza
caracterul din cuvint in partea dreapta; deci pointerii char
sint masurati in unitati de 2 la 16 bytes; orice altceva in
unitati de 2 la 18 cuvinte; double si agregatele care le contin
trebuie sa fie la adresa de cuvint para.
IBM 370 si Interdata 8/32 sint similare. La ambele adresele
se masoara in bytes; obiectele elementare sint aliniate la
limite egale cu lungimea lor; pointeri catre short sint0 mod 2,
catre int sau float 0 mod 4 si la double 0 mod 8. Agregatele sint
aliniate la limitele stricte necesitate de constituenti.
15. Expresii 'constante'
In multe locuri C necesita expresii care dau o constanta: dupa
case, ca limite de tablouri, la initializari. In primele 2,
expresiile pot cuprinde doar constante intregi, constante
caracter, expresii tip sizeof conectate la operatorii binari:
+ - * / % & ^ << >> == != <> <= >=
Sau prin operatorii unari:
- ~
Sau prin operatorul ternar:
? :
Parantezele sint folosite pt grupare, nu pt apeluri de functii. O
latitudine mai mare o permit initializarile; in afara de
expresiile constante se poate aplica operatorul unar & la
obiecte externe sau statice, sau la tablouri externe sau
statice avind ca indici expresii constante.
Operatorul unar & poate fi aplicat implicit prin aaparitia de
tablouri fara indici sau functii. Regula de baza este ca
initializarile conduc la o constanta sau la o adresa a unui obiect
extern sau static plus sau minus o constanta.
16. Consideratii de portabilitate
Unele parti din C sint inerent dependente de masina. Lista care
urmeaza contine sursele de prorbleme cele mai importante:
Lungimea cuvintului de memorie si proprietatea aritmeticei in VF
sau impartirea intregilor au dovedit in practica ca nu sint
o problema. Alte fatete ale hardware-ului sint reflectate in
diversele implementari. Unele din ele, ca extensia de semn (
convertirea unui caracter negativ intr-un inttreg) si ordinea
bytelor in cuvint, sint neplaceri care trebuie observate atent.
Altele sint probleme minore.
Numarul de variabile register care pot fi plasate efectiv in
registre depind de la masina la masina, ca si seturi de
tipuri valide. Compilatoarele fac lucrurile corespunzator
propriei masini; declaratiile register excesive sau invalide
sint ignorate.
Unele dificultati cresc cind se folosesc practici de codificare
dubioase. Nu este recomandat a se scrie programe care depind de
aceasta proprietate.
Ordinea de evaluare a argumentelor functiilor nu este specifi
cata de limbaj. La PDP-11 este de la dreapta la stinga, la
altele de la stinga la dreapta. Ordinea de aparitie a efectelor
secundare nu e specificata.
Daca constantele caracter sint obiecte de tipul int,
constantele caracter multicaracter sin permise. Implementarea
specifica depinde de masina pt ca ordinea in care caracterele
sint plasate in cuvint variaza de la o masina la alta.
Cimpurile apar in cuvint si caracterele in intregi de la dreapta
la stinga in PDP si de la stinga la dreapta in alte masini. Aceste
diferente sint invizibile in programe izolate care nu fac
apel la dependente de tip (de exemplu conversia din pointer
int in pointer char si implementarea memoriei pointate) dar
trebuie considerate daca se doreste conformarea cu modalitatile de
memorare externa.
Limbajul acceptat de diversele compilatoare difera putin. Dar,
compilatorul pt PDP=11 folosit curent nu initializeaza structuri
de cimpuri de biti, nu accepta operatori de asignare in unele
contexte in care se foloseste valoarea asignarii.
17. Anacronisme
C este un limbaj in evolutie, unele constructii invechite pot fi
intilnite in programe mai vechi. Unele compilatoare suporta aceste
anacronisme, ele fiind pe cale de disparitie, raminind doar
problema portabilitatii.
Versiunile mai vechi de C permiteau forma =op in locul lui op=
pt asignare. Acestea duceau la ambiguitati, cum ar fi
x=-1
care acum inseamna scaderea unui 1 din x, = si - fiind
adiacente, dar care poate insemna si asignarea lui -1 lui x.
Sintaxa initializarilor s-a schimbat; la inceput semnul =
care anunta un initializator nu era prezent, adica in loc de
int x = 1;
se folosea
int x 1;
modificarea s-a facut pentru ca initializarea
int f(1+2)
semana cu o declaratie de functie atit de mult incit deranja
compilatoarele.
18. Sumar al sintaxei
Acest numar al sintaxei C-ului are scopul de a ajuta
intelegerea sa mai mult decit de a defini exact limbajul.
18. 1. Expresii
Expresii de baza sint:
expression:
primary
*expression
&expression
-expression
!expression
~expression
++lvalue
--lvalue
lvalue++
lvalue--
sizeof expression
(type-name)expression
expression binop expression
expression?expression:expression
lvalue asgnop expression
exprerssion, expression
primary:
identifier
constant
string
(expression)
primary(expression-listopt)
primary[expression]
lvalue. identifier
primary->identifier
lvalue:
identifier
primary[expression]
lvalue. identifier
primary->identifier
*expression
(lvalue)
Operatorii expresiilor primare
() []. ->
au cea mai mare prioritate si grupeaza stinga la dreapta.
Operatorii unari:
* & - ! ~ ++ -- sizeof(type-name)
au prioritatea sub cea a operatorilor primari dar mai mare decit a
operatorilor binari si grupeaza de la dreapta la stinga.
Operatorii binari si operatorul conditional grupeaza stinga la
dreapta si au priortatea descrescind asa cum e indicat
binop:
* / %
+ -
>> <<
< > <= >=
== !=
&
^
|
&&
?!
Operatorii de asignare au aceeasi prioritate
asgnop:
= += -= *= /=, %= >>= <<= &= ^= =
Operatorul, au cea mai mica prioritate, grupeaza stinga spre
dreapta
18. 2. Declaratii
declaration:
decl-specifiers init-declarator-listopt;
decl-specifiers:
type-specifier decl-specifiersopt
-specifier decl-specifiersopt
sc-specifier:
auto
static
extern
register
typedef
type-specifier:
char
short
int
long
unsigned
float
double
struct-or-union-specifier
typedef-name
init-declaration-list:
init-declarator
init-declarator, init-declarator-list
init-declarator:
declarator initializeropt
declarator:
identifier
(declarator)
*declarator
declarator()
declarator[constant-expressionopt]
struct-or-union-specifier:
struct
struct identifier
struct identifier
union
union identifier
union identifier
struct-decl-list:
struct-declaration
struct-declaration struct-decl-list
struct-declaration:
type-specifier struct-declarator-list;
struct-declarato-list:
struct-declarator
struct-declarator, struct-declarator-list
struct-declarator:
declarator
declarator:constant-expression
:constant-expression
initializer:
=expression
=
=
initializer-list:
expression
initializer-list, initializer-list
type-name:
type-specifier abstract-declarator
abstract-declarator:
empty
(abstract-declarator)
*abstract-declarator
abstract-declarator()
abstract-declarator[constant-expressionopt]
typedef-name:
identifier
18. 3. Enunturi
compound-statement:
declaration-list:
declaration
declaration declaration-list
statement-list
statement
statement statement-list
statement:
compound-statement
expression;
if(expression)statement
if(expression)statement else statement
while(expression)stament
do statement while(expression);
for(expression-1opt;expression-2opt;expression-3opt)statement
switch(expression)statement
case constant-expression:statement
default:statement
break;
continue;
return;
return expression;
goto identifier;
identifier:statement
;
18. 4. Definitii externe
program:
external-definition
external-definition program
external-definition:
function-definition
data-definition
function-definition
type-specifieropt function-declarator function-body
function-declarator
declarator(parameter-listopt)
parameter-list
identifier
identifier, parameter-list
function-body:
type-decl-list function-statement
function-statement
data-definition
externopt type-specifieropt init-declarator-listopt
staticopt type-specifieropt init-declarator-listopt
18. 5. Preprocesor
#define identifier token-string
#define identifier(identifier, , identifier)token-string
#undef identifier
#include 'filname'
#include <filname>
#if constant-expression
#ifdef identifier
#ifndef identifier
#else
#endif
#line constant identifier
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1386
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved