Appunti per Scuola e Università
humanisticheUmanistiche
Appunti e tesine di tutte le materie per gli studenti delle scuole medie riguardanti le materie umanistiche: dall'italiano alla storia riguardanti le materie umanistiche: dall'italiano alla storia 
sceintificheScientifiche
Appunti, analisi, compresione per le scuole medie suddivisi per materie scientifiche, per ognuna troverai appunti, dispense, esercitazioni, tesi e riassunti in download.
tecnicheTecniche
Gli appunti, le tesine e riassunti di tecnica amministrativa, ingegneria tecnico, costruzione. Tutti gli appunti di AppuntiMania.com gratis!
Appunti
informatica
CComputerDatabaseInternetJava
Linux unixReti


AppuntiMania.com » Informatica » Appunti di c » L'accessibilitÀ e la durata delle variabili

L'accessibilitÀ e la durata delle variabili




Visite: 1355Gradito:apreciate 5-stela [ Medio appunti ]
Leggi anche appunti:

L'accessibilitÀ e la durata delle variabili


L'accessibilità e la durata delle variabili In C le variabili possono essere

L'i/o e la gestione dei file


L'I/O e la gestione dei file Per Input/Output (I/O) si intende l'insieme delle

Impiego del costrutto monitor


Impiego del costrutto monitor             X) Si implementi il problema dei
immagine di categoria

Scarica gratis L'accessibilitÀ e la durata delle variabili

L'accessibilità e la durata delle variabili

In C le variabili possono essere classificate, oltre che secondo il tipo di dato, in base alla loro accessibilità e alla loro durata. In particolare, a seconda del contesto in cui sono dichiarate, le variabili di un programma C assumono per default determinate caratteristiche di accessibilità e durata; in molti casi, però, queste possono essere modificate mediante l'utilizzo di apposite parole chiave applicabili alla dichiarazione delle variabili stesse.

Per comprendere i concetti di accessibilità (o visibilità) e durata, va ricordato che una variabile altro non è che un'area di memoria, grande quanto basta per contenere un dato del tipo indicato nella dichiarazione, alla quale il compilatore associa, per comodità del programmatore, il nome simbolico da questi scelto.

In termini generali, possiamo dire che la durata di una variabile si estende dal momento in cui le viene effettivamente assegnata un'area di memoria fino a quello in cui quell'area è riutilizzata per altri scopi.

Dal punto di vista dell'accessibilità ha invece rilevanza se sia o no possibile leggere o modificare, da parti del programma diverse da quella in cui la variabile è stata dichiarata, il contenuto dell'area di RAM riservata alla variabile stessa

Cerchiamo di mettere un po' d'ordine

Le variabili automatic

Qualsiasi variabile dichiarata all'interno di un blocco di codice racchiuso tra parentesi graffe (generalmente all'inizio di una funzione) appartiene per default alla classe automatic. Non è dunque necessario, anche se è possibile farlo, utilizzare la parola chiave auto. La durata e la visibilità della variabile sono entrambe limitate al blocco di codice in cui essa è dichiarata. Se una variabile è dichiarata in testa ad una funzione, essa esiste (cioè occupa memoria) dal momento in cui la funzione inizia ad essere eseguita, sino al momento in cui la sua esecuzione termina.

Le variabili automatic, dunque, non occupano spazio di memoria se non quando effettivamente servono; inoltre, essendo accessibili esclusivamente dall'interno di quella funzione, non vi è il rischio che possano essere modificate accidentalmente da operazioni svolte in funzioni diverse su variabili aventi medesimo nome: in un programma C, infatti, più variabili automatic possono avere lo stesso nome, purché dichiarate in blocchi di codice diversi. Se i blocchi sono nidificati (cioè uno è interamente all'interno di un altro) ciò è ancora vero, ma la variabile dichiarata nel blocco interno 'nasconde' quella dichiarata con identico nome nel blocco esterno (quando, ovviamente, viene eseguito il blocco interno).

Vediamo un esempio:

#include <stdio.h>


void main(void)


printf('%d, %dn',x,y);


La variabile x dichiarata in testa alla funzione main() è inizializzata a  , mentre la x dichiarata nel blocco interno è inizializzata a  . L'output del programma é:



Ciò prova che la 'prima' x esiste in tutta la funzione main(), mentre la 'seconda' esiste ed è visibile solo nel blocco più interno; inoltre, dal momento che le due variabili hanno lo stesso nome, nel blocco interno la prima x è resa non visibile dalla seconda. La y, invece, è visibile anche nel blocco interno.

Se si modifica il programma dell'esempio come segue:

#include <stdio.h>


void main(void)


printf('%d, %dn',x,y,z);


il compilatore non porta a termine la compilazione e segnala l'errore con un messaggio analogo a 'undefined symbol z in function main()' a significare che la seconda printf() non può referenziare la variabile z, poiche questa cessa di esistere al termine del blocco interno di codice.

La gestione delle variabili automatic è dinamica. La memoria necessaria è allocata alla variabile esclusivamente quando viene eseguito il blocco di codice (tipicamente una funzione) in cui essa è dichiarata, e le viene 'sottratta' non appena il blocco termina. Ciò implica che non è possibile conoscere il contenuto di una variabile automatic prima che le venga esplicitamente assegnato un valore da una istruzione facente parte del blocco (vedere pag.  ): a beneficio dei distratti, vale la pena di evidenziare che una variabile automatica può essere utilizzata in lettura prima di essere inizializzata , ma il valore in essa contenuto è casuale e, pertanto, inutilizzabile nella quasi totalità dei casi.

E' opportuno sottolineare che mentre le variabili dichiarate nel blocco più esterno di una funzione (cioè in testa alla stessa) esistono e sono visibili (salvo il caso di variabili con lo stesso nome) in tutti i blocchi interni di quella funzione, nel caso di funzioni diverse nessuna di esse può accedere alle variabili automatiche delle altre.

Le variabili register

Dal momento che il compilatore colloca le variabili automatic nella RAM del calcolatore, i valori in esse contenuti devono spesso essere copiati nei registri della CPU per poter essere elaborati e, se modificati dall'elaborazione subita, copiati nuovamente nelle locazioni di memoria di provenienza. Tali operazioni sono svolte in modo trasparente per il programmatore, ma possono deteriorare notevolmente la performance di un programma, soprattutto se ripetute più e più volte (ad esempio all'interno di un ciclo con molte iterazioni).

Dichiarando una variabile automatic con la parola chiave register si forza il compilatore ad allocarla direttamente in un registro della CPU, con notevole incremento di efficienza nell'elaborazione del valore in essa contenuto. Ecco un esempio:

register int i = 10;


do while(i--);

Il ciclo visualizza, incolonnati , i numeri da  ; la variabile i si comporta come una qualsiasi variabile automatic, ma essendo probabilmente gestita in un registro consente un'elaborazione più veloce. E' d'obbligo scrivere 'probabilmente gestita' in quanto non si può essere assolutamente certi che il compilatore collochi una variabile dichiarata con register proprio in un registro della CPU: in alcune situazioni potrebbe gestirla come una variabile automatic qualsiasi, allocandola in memoria. I principali motivi sono due: la variabile potrebbe occupare più byte di quanti compongono un registro della CPU , o potrebbero non esserci registri disponibili allo scopo

Già che ci siamo, diamo un'occhiata più approfondita all'esempio di poco fa. Innanzitutto va rilevato che nella dichiarazione di i potrebbe essere omessa la parola chiave int (vedere pag. 

register i = 10;

Abbiamo poi utilizzato un costrutto nuovo: il ciclo dowhile. Esso consente di identificare un blocco di codice (quello compreso tra le graffe) che viene eseguito finché la condizione specificata tra parentesi dopo la parola chiave while continua ad essere vera. Il ciclo viene sempre eseguito almeno una volta, perché il test è effettuato al termine del medesimo (pag.  ). Nel nostro caso, quale test viene effettuato? Dal momento che non è utilizzato alcun operatore di confronto esplicito (pag.  ), viene controllato se il risultato dell'espressione nelle tonde è diverso da  . L'operatore , detto di autodecremento (pag.  ), è specificato dopo la variabile a cui è applicato. Ciò assicura che i sia decrementata dopo l'effettuazione del test. Perciò il ciclo è eseguito 11 volte, con i che varia da  inclusi. Se l'espressione fosse --i, il decremento sarebbe eseguito prima del test, con la conseguenza che per i pari a  il ciclo non verrebbe più eseguito.

Come per le variabili automatic, non è possibile conoscere il contenuto di una variabile register prima della sua esplicita inizializzazione mediante un operazione di assegnamento. In questo caso non si tratta di utilizzo e riutilizzo di un'area di memoria, ma di un registro macchina: non possiamo conoscerne a priori il contenuto nel momento in cui esso è destinato alla gestione della variabile (dichiarazione della variabile). Inoltre, analogamente alle variabili automatic, anche quelle register cessano di esistere all'uscita del blocco di codice (solitamente una funzione) nel quale sono dichiarate e il registro macchina viene utilizzato per altri scopi.

Le variabili register, a differenza delle automatic, non hanno indirizzo: ciò appare ovvio se si pensa che i registri macchina si trovano nella CPU e non nella RAM. La conseguenza immediata è che una variabile register non può mai essere referenziata tramite un puntatore. Nel nostro esempio, il tentativo di assegnare ad un puntatore l'indirizzo di i provocherebbe accorate proteste da parte del compilatore.

register i;

int *iPtr = &i; // errore! i non ha indirizzo

Pur non avendo indirizzo, le variabili register possono contenere un indirizzo, cioè un puntatore: la dichiarazione

register char *ptr_1, char *ptr_2;

non solo è perfettamente lecita, ma anzi genera, se possibile, due puntatori (a carattere) particolarmente efficienti.

Le variabili static

Una variabile è static se dichiarata utilizzando, appunto, la parola chiave static

static float sF, *sFptr;

Nell'esempio sono dichiarate due variabili static: una di tipo float e un puntatore (static anch'esso) ad un float

Come nel caso delle variabili automatic, quelle static sono locali al blocco di codice in cui sono dichiarate (e dunque sono accessibili solo all'interno di esso). La differenza consiste nel fatto che le variabili static hanno durata estesa a tutto il tempo di esecuzione del programma. Esse, pertanto, esistono già prima che il blocco in cui sono dichiarate sia eseguito e continuano ad esistere anche dopo il termine dell'esecuzione del medesimo.

Ne segue che i valori in esse contenuti sono persistenti; quindi se il blocco di codice viene nuovamente eseguito esse si presentano con il valore posseduto al termine dell'esecuzione precedente.

In altre parole, il compilatore alloca in modo permanente alle variabili static la memoria loro necessaria.

Il tutto può essere chiarito con un paio di esempi:

#include <stdio.h>


void incrementa(void)



void main(void)


Il programma chiama la funzione incrementa() 3 volte; ad ogni chiamata la variabile x, automatic, è dichiarata ed inizializzata a  . Essa è poi incrementata e visualizzata. L'output del programma è il seguente:




Infatti x, essendo una variabile automatic, 'sparisce' al termine dell'esecuzione della funzione in cui è dichiarata. Ad ogni chiamata essa è nuovamente allocata, inizializzata a  , incrementata, visualizzata e buttata alle ortiche. Indipendentemente dal numero di chiamate, incrementa() visualizza sempre il valore 

Riprendiamo ora la funzione incrementa(), modificando però la dichiarazione di x

void incrementa(void)


Questa volta x è dichiarata static. Vediamo l'output del programma:




La x è inizializzata a  solo una volta, al momento della compilazione. Durante la prima chiamata ad incrementa(), essa assume pertanto valore  . Poiché x static, il suo valore è persistente e non viene perso in uscita dalla funzione. Ne deriva che alla seconda chiamata di incrementa() essa assume valore  e, infine,  alla terza chiamata.

Quando si specifica un valore iniziale per una variabile automatic, detto valore è assegnato alla variabile ogni volta che viene eseguito il blocco in cui la variabile stessa è dichiarata. Una inizializzazione come:



void main(void)


L'output del programma è il seguente:




Infatti la variabile x, essendo definita al di fuori di qualunque funzione, è accessibile sia in main() che in incrementa() e il suo valore è conservato per tutta la durata dell'esecuzione.

Se una variabile external (o globale) ha nome identico a quello di una variabile automatic (o locale), quest'ultima 'nasconde' la prima. Il codice che segue:

#include <stdio.h>


int x = 123;


void main(void)


printf('%dn',x);


produce il seguente output:




Infatti la x locale dichiarata nel blocco di codice interno a main() nasconde la x globale, dichiarata fuori dalla funzione; tuttavia la variabile locale cessa di esistere alla fine del blocco, pertanto quella globale è nuovamente accessibile.

Anche le variabili external, come quelle static, sono inizializzate dal compilatore al momento della compilazione, ed è loro attribuito valore  se il programmatore non indica un valore iniziale contestualmente alla dichiarazione.

Come abbiamo visto, le variabili external devono essere dichiarate al di fuori delle funzioni, senza necessità di specificare alcuna particolare parola chiave. Tuttavia, esse possono (ma non è obbligatorio) essere dichiarate anche all'interno delle funzioni che le referenziano, questa volta necessariamente precedute dalla parola chiave extern

#include <stdio.h>


int x = 123;


void main(void)


In effetti il compilatore non richiede che le variabili external vengano dichiarate all'interno delle funzioni, ma in questo caso è necessario che tali variabili siano state dichiarate al di fuori della funzione e in linee di codice precedenti quelle della funzione stessa, come negli esempi precedenti. Se tali condizioni non sono rispettate il compilatore segnala un errore di simbolo non definito:

#include <stdio.h>


int x = 123;


void main(void)



int y = 321;

Il codice dell'esempio è compilato correttamente se si dichiara extern la y in main()

#include <stdio.h>


int x = 123;


void main(void)



int y = 321;

Il problema può essere evitato dichiarando tutte le variabili globali in testa al sorgente, ma se una variabile external e una funzione che la referenzia sono definite in due file sorgenti diversi , è necessario comunque dichiarare la variabile nella funzione.

E' opportuno limitare al massimo l'uso delle funzioni external: il loro utilizzo indiscriminato, infatti, può generare risultati catastrofici. In un programma qualsiasi è infatti piuttosto facile perdere traccia del significato delle variabili, soprattutto quando esse siano numerose. Inoltre le variabili globali sono generate al momento della compilazione ed esistono durante tutta l'esecuzione, incrementando così lo spazio occupato dal file eseguibile e la quantità memoria utilizzata dallo stesso. Infine, con esse non è possibile utilizzare nomi localmente significativi (cioè significativi per la funzione nella quale vengono di volta in volta utilizzate) e si perde la possibilità di mantenere ogni funzione una entità a se stante, indipendente da tutte le altre.

Va infine osservato che una variabile external può essere anche static

#include <stdio.h>


static int x = 123;


void main(void)


Dichiarando static una variabile globale se ne limita la visibilità al solo file in cui essa è dichiarata: nel caso di un codice suddiviso in più sorgenti, le funzioni definite in altri file non saranno in grado di accedere alla x neppure qualora essa venga dichiarata con extern al loro interno. Naturalmente è ancora possibile dichiarare extern la variabile nelle funzioni definite nel medesimo file:

#include <stdio.h>


static int x = 123;


void main(void)


Come facilmente desumibile dall'esempio, la parola chiave static non deve essere ripetuta.




 Il compilatore, però, si degna di emettere un apposito warning.

 Nella stringa di formato passata a printf(), il  che compare tra l'indicatore di carattere di formato (' ') e il carattere di formato stesso ('d') serve quale specificatore dell'ampiezza di campo. In altre parole esso indica che il valore contenuto nella variabile i deve essere visualizzato in uno spazio ampio 2 caratteri, assicurando così il corretto incolonnamento dei numeri visualizzati.

 Le macchine 8086, 8088 e 80286 dispongono esclusivamente di registri a 16 bit. Una dichiarazione come la seguente:

register long rLong;

non potrebbe che originare, su tali macchine, una normale variabile automatic, perché il tipo long integer occupa 32 bit. Su macchine 80386 (e superiori), invece, il compilatore potrebbe gestire rLong in un registro, dal momento che detti elaboratori dispongono di registri a 32 bit (a seconda del compilatore, però, potrebbe essere necessario specificare esplicitamente in fase di compilazione che si desidera generare codice eseguibile specifico per macchine 80386).

 In effetti, il numero dei registri macchina è limitato. E' quindi opportuno identificare le variabili più utilizzate e dichiararle per prime come register: il compilatore alloca le variabili nell'ordine in cui sono dichiarate.

 Suddividere il codice di un programma molto 'corposo' in più file sorgenti può facilitarne la manutenzione, ma soprattutto consente, in caso di modifche, di ricompilare solo le parti effettivamente modificate, a tutto vantaggio dell'efficienza del processo di programmazione.

Scarica gratis L'accessibilitÀ e la durata delle variabili
Appunti su:



Scarica 100% gratis e , tesine, riassunti



Registrati ora

Password dimenticata?
  • Appunti superiori
  • In questa sezione troverai sunti esame, dispense, appunti universitari, esercitazioni e tesi, suddivisi per le principali facoltà.
  • Università
  • Appunti, dispense, esercitazioni, riassunti direttamente dalla tua aula Universitaria
  • all'Informatica
  • Introduzione all'Informatica, Information and Comunication Tecnology, componenti del computer, software, hardware ...