C Language
Ambito dell'identificatore
Ricerca…
Block Scope
Un identificatore ha scope di blocco se la relativa dichiarazione appare all'interno di un blocco (si applica la dichiarazione dei parametri nella definizione della funzione). L'oscilloscopio termina alla fine del blocco corrispondente.
Nessuna entità diversa con lo stesso identificatore può avere lo stesso ambito, ma gli ambiti possono sovrapporsi. In caso di ambiti sovrapposti, l'unico visibile è quello dichiarato nello scope più interno.
#include <stdio.h>
void test(int bar) // bar has scope test function block
{
int foo = 5; // foo has scope test function block
{
int bar = 10; // bar has scope inner block, this overlaps with previous test:bar declaration, and it hides test:bar
printf("%d %d\n", foo, bar); // 5 10
} // end of scope for inner bar
printf("%d %d\n", foo, bar); // 5 5, here bar is test:bar
} // end of scope for test:foo and test:bar
int main(void)
{
int foo = 3; // foo has scope main function block
printf("%d\n", foo); // 3
test(5);
printf("%d\n", foo); // 3
return 0;
} // end of scope for main:foo
Funzione Prototipo Ambito
#include <stdio.h>
/* The parameter name, apple, has function prototype scope. These names
are not significant outside the prototype itself. This is demonstrated
below. */
int test_function(int apple);
int main(void)
{
int orange = 5;
orange = test_function(orange);
printf("%d\r\n", orange); //orange = 6
return 0;
}
int test_function(int fruit)
{
fruit += 1;
return fruit;
}
Si noti che si ottengono messaggi di errore enigmatici se si introduce un nome di tipo in un prototipo:
int function(struct whatever *arg);
struct whatever
{
int a;
// ...
};
int function(struct whatever *arg)
{
return arg->a;
}
Con GCC 6.3.0, questo codice (file di origine dc11.c
) produce:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c dc11.c
dc11.c:1:25: error: ‘struct whatever’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
int function(struct whatever *arg);
^~~~~~~~
dc11.c:9:9: error: conflicting types for ‘function’
int function(struct whatever *arg)
^~~~~~~~
dc11.c:1:9: note: previous declaration of ‘function’ was here
int function(struct whatever *arg);
^~~~~~~~
cc1: all warnings being treated as errors
$
Posiziona la definizione della struttura prima della dichiarazione della funzione o aggiungi struct whatever;
come una riga prima della dichiarazione della funzione, e non ci sono problemi. Non dovresti introdurre nuovi nomi di tipi in un prototipo di funzione perché non c'è modo di usare quel tipo, e quindi non c'è modo di definire o usare quella funzione.
Scopo del file
#include <stdio.h>
/* The identifier, foo, is declared outside all blocks.
It can be used anywhere after the declaration until the end of
the translation unit. */
static int foo;
void test_function(void)
{
foo += 2;
}
int main(void)
{
foo = 1;
test_function();
printf("%d\r\n", foo); //foo = 3;
return 0;
}
Ambito di funzione
L'ambito della funzione è lo scopo speciale per le etichette . Ciò è dovuto alla loro proprietà insolita. Un'etichetta è visibile attraverso l'intera funzione che è definita e si può saltare (usando l' label
goto
dell'istruzione) ad essa da qualsiasi punto nella stessa funzione. Anche se non utile, il seguente esempio illustra il punto:
#include <stdio.h>
int main(int argc,char *argv[]) {
int a = 0;
goto INSIDE;
OUTSIDE:
if (a!=0) {
int i=0;
INSIDE:
printf("a=%d\n",a);
goto OUTSIDE;
}
}
INSIDE
può sembrare definito all'interno del blocco if
, come nel caso di i
che scope è il blocco, ma non lo è. È visibile nell'intera funzione mentre l'istruzione goto INSIDE;
illustra. Quindi non ci possono essere due etichette con lo stesso identificatore in una singola funzione.
Un possibile utilizzo è il seguente schema per realizzare corrette puliture complesse delle risorse allocate:
#include <stdlib.h>
#include <stdio.h>
void a_function(void) {
double* a = malloc(sizeof(double[34]));
if (!a) {
fprintf(stderr,"can't allocate\n");
return; /* No point in freeing a if it is null */
}
FILE* b = fopen("some_file","r");
if (!b) {
fprintf(stderr,"can't open\n");
goto CLEANUP1; /* Free a; no point in closing b */
}
/* do something reasonable */
if (error) {
fprintf(stderr,"something's wrong\n");
goto CLEANUP2; /* Free a and close b to prevent leaks */
}
/* do yet something else */
CLEANUP2:
close(b);
CLEANUP1:
free(a);
}
Etichette come CLEANUP1
e CLEANUP2
sono identificatori speciali che si comportano in modo diverso da tutti gli altri identificativi. Sono visibili da qualsiasi parte all'interno della funzione, anche in posizioni che sono eseguite prima dell'istruzione etichettata, o anche in luoghi che non potrebbero mai essere raggiunti se nessuno dei goto
viene eseguito. Le etichette sono spesso scritte in lettere minuscole e non maiuscole.