Function scope is the special scope for labels. This is due to their unusual property. A label is visible through the entire function it is defined and one can jump (using instruction goto
label
) to it from any point in the same function. While not useful, the following example illustrate the point:
#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
may seem defined inside the if
block, as it is the case for i
which scope is the block, but it is not. It is visible in the whole function as the instruction goto INSIDE;
illustrates. Thus there can't be two labels with the same identifier in a single function.
A possible usage is the following pattern to realize correct complex cleanups of allocated ressources:
#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);
}
Labels such as CLEANUP1
and CLEANUP2
are special identifiers that behave differently from all other identifiers. They are visible from everywhere inside the function, even in places that are executed before the labeled statement, or even in places that could never be reached if none of the goto
is executed. Labels are often written in lower-case rather than upper-case.