Ошибка повторного использования переменной цикла for в цикле
Рассмотрим этот фрагмент программы C:
for(int i = 0; i < 5; i++)
{
int i = 10; // <- Note the local variable
printf("%d", i);
}
Он компилируется без какой-либо ошибки, и, когда он выполняется, он дает следующий результат:
1010101010
Но если я напишу аналогичный цикл в C++:
for(int i = 0; i < 5; i++)
{
int i = 10;
std::cout << i;
}
Ошибка компиляции с этой ошибкой:
prog.cc:7:13: error: redeclaration of 'int i'
int i = 10;
^
prog.cc:5:13: note: 'int i' previously declared here
for(int i = 0; i < 5; i++)
^
Почему это происходит?
Ответы
Ответ 1
Это связано с тем, что языки C и C++ имеют разные правила относительно повторного объявления переменных в области, вложенной в цикл for
:
-
C++
помещает i
в область тела цикла, так что второй int я = 10
является повторной декларацией, которая запрещена -
C
разрешает повторную декларацию в области внутри цикла for
; самая внутренняя переменная "выигрывает"
Ниже приведена демонстрация запущенной программы на C, а программа C++ не скомпилирована.
Открытие вложенной области внутри тела фиксирует ошибку компиляции (demo):
for (int i =0 ; i != 5 ; i++) {
{
int i = 10;
cout << i << endl;
}
}
Теперь i
в заголовке for
и int я = 10
находятся в разных областях, поэтому программе разрешено работать.
Ответ 2
В отличие от C, C++ имеет правило,
C++ 11-§6.5.3/1:
Заявление for
for ( for-init-statement conditionopt ; expressionopt ) statement
эквивалентно
{
for-init-statement
while ( condition ) {
statement
expression ;
}
}
за исключением того, что имена, объявленные в for-init-statement, находятся в той же декларативной области, что и объявленные в условии [...]
Это означает, что область действия for-init-statement
и statement
одинаковы *, а приведенный ниже код вызовет ошибку
for(int i = 0; i < 5; i++){
int i = 10; // Invalid.
// ...
}
В C,
C11- §6.8.5/5:
Оператор итерации представляет собой блок, область видимости которого является строгим подмножеством области его охватывающего блока. Тело цикла также является блоком, область видимости которого является строгим подмножеством области действия итерации.
Следовательно, statement
имеет свою собственную область действия, и приведенный выше код действителен и эквивалентен
for(int i = 0; i < 5; i++){
{
int i = 10; // Valid.
// ...
}
}
Предлагаемое чтение: n3337: 6.5.1 Оператор while/p (2).Такую же ссылку можно найти в C++ 17 draft (n4659) в разделе § 9.5.1 и §9.5.3.
Ответ 3
Это не переделка.
Смотрите внимательно...
for(int i = 0; i < 7; i++)
{
printf("i = %d\n", i);
int i = 5;
printf("new i = %d\n", i);
}
Вывод вышеуказанного кода: -
i = 0
new i = 5
i = 1
new i = 5
i = 2
new i = 5
i = 3
new i = 5
i = 4
new i = 5
i = 5
new i = 5
i = 6
new i = 5
Ясно, что существуют два разных i
Более новый i
имеет более локальную область.
Это ошибка?
нет
В чем цель?
Если это не разрешено, может быть очень сложно поддерживать крупные проекты, так как вы постоянно сталкиваетесь с именованием коллизий.
Как правило, хотя очень плохой практикой является предоставление одинакового имени различным переменным в разных областях, вы должны избегать этого, когда это возможно.
Почему нет предупреждающего сообщения?
Используйте gcc file_name.c -Wshadow
для компиляции.
EDIT: вы также можете локально блокировать первоначально объявленные переменные, обновляя их для циклов.