Я не понимаю, как работает следующий код:
#include "stdio.h"
int main(void) {
int i = 3;
while(i--) {
static int i = 100;
i--,
printf("%d\n", i);
}
return 0;
}
Код, скомпилированный с использованием Clang или GCC, выводит следующий вывод:
99
98
97
Может кто-нибудь объяснить мне, что здесь происходит? Похоже, что две операции выполняются в одной инструкции и более одного раза. Это неопределенное поведение?
Я наблюдаю такое же поведение в C ++.
Это не неопределенное поведение.
#include "stdio.h"
int main(void) {
int i = 3; //first i
while(i--) {
static int i = 100; //second i
i--,
printf("%d\n", i);
}
return 0;
}
В то время как петли тела самое местное i
(второй i
) является предпочтительным. При проверке состояния в цикле while он не знает, что находится в теле. Так что нет проблем с выбором первого i
,
Википедия говорит очень важную вещь об этом:
В компьютерном программировании переменная слежка происходит, когда переменная, объявленная в определенной области (блок решения, метод или внутренний класс), имеет то же имя, что и переменная, объявленная во внешней области. На уровне идентификаторов (имен, а не переменных) это называется маскированием имен. Говорят, что эта внешняя переменная скрыта внутренней переменной, а внутренний идентификатор маскирует внешний идентификатор.
Теперь здесь внутри блока он находит статическую переменную и работает с ней, но условие while уменьшает значение i
который объявлен вне блока. Сфера охвата отличается — нет проблем с использованием правильного значения i
, Это допустимый C-код, но не обязательно хороший способ написания вещей.
На самом деле делает это gcc -Wshadow progname.c
дает
progname.c: In function 'main':
progname.c:7:20: warning: declaration of 'i' shadows a previous local [-Wshadow]
static int i=2;
^
progname.c:5:9: warning: shadowed declaration is here [-Wshadow]
int i=2;
^
Из стандартного §6.2.1p4
… Если идентификатор обозначает два разных объекта в одном и том же пространстве имен, области действия могут перекрываться. Если это так, область действия одной сущности (внутренняя область) заканчивается строго перед областью действия другой сущности (внешняя область). Во внутренней области видимости обозначает сущность, объявленную во внутренней области; сущность, объявленная во внешней области видимости, скрыта (и не видна) во внутренней области видимости..
Возможно объявить переменную с таким же именем внутри вложенной области видимости. Компилятор видит их как разные переменные. Это очень запутанно, но переменная, к которой вы обращаетесь каждый раз, является той, которая объявлена в самой внутренней области видимости. Вне while
это int i = 3;
и внутри это static int i = 100;
#include "stdio.h"
int main(void) {
int i = 3; // outer i
while(i--) { // outer i
static int i = 100; // inner i
i--, // inner i
printf("%d\n", i); // inner i
}
return 0;
}
Если бы это была функция, отличная от main, то при втором вызове
96
95
94
и так далее…