C Language
Область идентификатора
Поиск…
Область применения
Идентификатор имеет область блока, если соответствующее объявление появляется внутри блока (применяется объявление параметра в определении функции). Область заканчивается в конце соответствующего блока.
Никакие другие объекты с одним и тем же идентификатором не могут иметь одинаковую область видимости, но области могут перекрываться. В случае пересекающихся областей видимость видима только одна, заявленная в самой внутренней области.
#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
Функция Prototype Scope
#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;
}
Обратите внимание, что вы получаете непонятные сообщения об ошибках, если ввести прототип названия типа:
int function(struct whatever *arg);
struct whatever
{
int a;
// ...
};
int function(struct whatever *arg)
{
return arg->a;
}
С GCC 6.3.0 этот код (исходный файл dc11.c
) создает:
$ 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
$
Поместите определение структуры перед объявлением функции или добавьте struct whatever;
как строка перед объявлением функции, и нет проблем. Вы не должны вводить новые имена типов в прототипе функции, потому что нет способа использовать этот тип, и, следовательно, нет способа определить или использовать эту функцию.
Область файла
#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;
}
Область действия
Область функций - это специальная область для ярлыков . Это связано с их необычным свойством. Метка отображается через всю функцию, которую она определена, и ее можно перескакивать (используя инструкцию goto
label
) из любой точки в той же функции. Хотя это не полезно, следующий пример иллюстрирует точку:
#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
может показаться определенным внутри блока if
, так как это имеет место для i
который является блоком, но это не так. Он виден во всей функции, поскольку инструкция goto INSIDE;
иллюстрирует. Таким образом, не может быть двух меток с одним и тем же идентификатором в одной функции.
Возможным использованием является следующий шаблон для реализации правильной комплексной очистки выделенных ресурсов:
#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);
}
Ярлыки, такие как CLEANUP1
и CLEANUP2
являются специальными идентификаторами, которые ведут себя по-другому от всех других идентификаторов. Они видны повсюду внутри функции, даже в местах, которые выполняются перед помеченным заявлением, или даже в местах, которые никогда не могут быть достигнуты, если ни одно из goto
не выполняется. Ярлыки часто пишутся в нижнем регистре, а не в верхнем регистре.