C Language
Ámbito identificador
Buscar..
Alcance del bloque
Un identificador tiene un ámbito de bloque si su declaración correspondiente aparece dentro de un bloque (se aplica la declaración de parámetros en la definición de función). El alcance finaliza al final del bloque correspondiente.
Ninguna entidad diferente con el mismo identificador puede tener el mismo alcance, pero los ámbitos pueden superponerse. En el caso de superposición de ámbitos, el único visible es el declarado en el ámbito más 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
Función de prototipo de alcance
#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;
}
Tenga en cuenta que recibe mensajes de error desconcertantes si introduce un nombre de tipo en un prototipo:
int function(struct whatever *arg);
struct whatever
{
int a;
// ...
};
int function(struct whatever *arg)
{
return arg->a;
}
Con GCC 6.3.0, este código (archivo fuente 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
$
Coloque la definición de la estructura antes de la declaración de la función, o agregue la struct whatever;
como una línea antes de la declaración de función, y no hay problema. No debe introducir nuevos nombres de tipo en un prototipo de función porque no hay manera de usar ese tipo y, por lo tanto, no hay manera de definir o usar esa función.
Alcance del archivo
#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;
}
Alcance de la función
El alcance de la función es el ámbito especial para las etiquetas . Esto se debe a su propiedad inusual. Una etiqueta es visible a través de toda la función que está definida y se puede saltar (usando la instrucción goto
label
) desde cualquier punto en la misma función. Si bien no es útil, el siguiente ejemplo ilustra el 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
puede parecer definido dentro del bloque if
, como es el caso para i
cuyo alcance es el bloque, pero no lo es. Es visible en toda la función como la instrucción goto INSIDE;
ilustra Por lo tanto, no puede haber dos etiquetas con el mismo identificador en una sola función.
Un posible uso es el siguiente patrón para realizar limpiezas complejas correctas de recursos asignados:
#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);
}
Las etiquetas como CLEANUP1
y CLEANUP2
son identificadores especiales que se comportan de manera diferente a todos los demás identificadores. Son visibles desde cualquier lugar dentro de la función, incluso en lugares que se ejecutan antes de la declaración etiquetada, o incluso en lugares a los que nunca se podría llegar si no se ejecuta ninguno de los goto
. Las etiquetas a menudo se escriben en minúsculas en lugar de mayúsculas.