Повторное объявление переменной внутри цикла в C

Я составил следующую программу, используя gcc prog.c -Wall -Wextra -std=gnu11 -pedantic команда on GCC компилятора. Я думал, он работает нормально, без каких-либо предупреждений или ошибок.

#include <stdio.h>

int main(void)
{
    for (int i = 0; i == 0;  i++) 
    {        
        printf("%dn", i);
        long int i = 1; // Why doesn't redeclaration error?
        printf("%ldn", i);
    }
}

почему компилятор не генерирует переменную redeclaration i ошибка?

5 ответов


из стандартных §6.8.5.5 (N1570)

оператор итерации-это блок, область действия которого является строгим подмножеством объем его ограждающего блока. тело цикла также является блоком, scope-это строгое подмножество области действия оператора итерации.

Курсив


на языке C область statement вложен в область for loop init-statement.

по данным Cppreference :

в то время как в C++ область init-оператора и область утверждение одно и то же, в C область statement вложен в рамках init-statement.

по данным stmt:

для заявление

for ( for-init-statement conditionopt ; expressionopt ) statement

эквивалентно

{
    for-init-statement
    while ( condition ) {
            statement
            expression ;
      }
} 

за исключением того, что имена, объявленные в инструкции for-init, находятся в той же декларативной области, что и имена, объявленные в условии, и за исключением того, что продолжение в заявлении (не прилагается к другому оператор итерации) будет выполнять выражение перед повторной оценкой состояние.


вы должны установить -Wshadow для получения предупреждений о затененных переменных. Переменное затенение разрешено в C.

но это крайний случай. ВАР, объявленный в голове а for конструкция не вне кронштейнов, потому что она не имеет никакой объем после конструкции.

это не эквивалентны:

int i;
for( i = 0; …)
{ … }
// is is still in scope but wouldn't if declared in the head of for

но, это не внутри скобок тоже.

for( i = 0; …)
{ 
  int i; // this would be strange, because i is used before it is declared.
  … 
}

лучшая аппроксимативная замена кода это:

{
  int i;
  for( i = 0; …)
  {
  … 
  }
}  // i loses scope

таким образом, это не redeclaration, а теневое объявление внутри тела цикла.


Why compiler doesn't generate redeclaration variable i error?

С Стандарты C#6.2.1p4 области идентификаторов

каждый другой идентификатор имеет область, определяемую размещением его объявления (в деклараторе или спецификаторе типа). Если Декларатор или спецификатор типа, объявляющий идентификатор, появляется вне любого блока или списка параметров, идентификатор имеет область файла, которая завершается в конце единицы перевода. Если Декларатор или спецификатор типа, объявляющий идентификатор, отображается внутри блока или в списке объявлений параметров в определении функции, идентификатор имеет область блока, которая завершается в конце связанного блока. Если Декларатор или спецификатор типа, объявляющий идентификатор, отображается в списке объявлений параметров в прототипе функции (не является частью определения функции), идентификатор имеет область прототипа функции, которая завершается в конце функции описатель. Если идентификатор обозначает два разных объекта в одном пространстве имен, области могут перекрываться. Если это так, то область одного объекта (внутренняя область) будет заканчиваться строго перед областью другого объекта (внешняя область). во внутренней области идентификатор обозначает сущность, объявленную во внутренней области; сущность, объявленная во внешней области, скрыта (и не видима) во внутренней области.

С стандарты C#6.8.5p5 Итераторы

оператор итерации-это блок, область действия которого является строгим подмножеством области его заключительного блока. Тело цикла также является блоком, область которого является строгим подмножеством области оператора итерации.

Итак, в этом коде:

for (int i = 0; i == 0;  i++)
{
    printf("%d\n", i);
    long int i = 1; // Why doesn't redeclaration error?
    printf("%ld\n", i);
}

область действия идентификатора с именем i перекрывается, и в этом пространстве имен i объявлен в for (int i = 0; i == 0; i++) и внешняя сфера и один объявленный в теле цикла long int i = 1; и внутренний объем.

внутри тела цикла, после этого утверждения:

long int i = 1;

на i объявленные во внешней области не отображается и printf() печать стоимостью i видимый во внутренней области, которая 1.

это поведение также известно как Переменной Тенизации что происходит, когда переменная, объявленная в определенной области, имеет то же имя как переменная, объявленная во внешней области.

язык C допускает переменное затенение, и именно поэтому компилятор не выдает никаких ошибок за это. Однако, в gcc компилятора, если вы используете -Wshadow опция вы получите предупреждающее сообщение -declaration shadows a local variable.


для дальнейшей проверки я проверил этот код в visual studio 2008 для prog.файл c. Я обнаружил, что компилятор дает ошибку в строке for (int i = 0; i == 0; i++) . Компилятор ожидает, что объявление i будет в начале самой программы. Такое поведение является правильным для файла c. Если объявление перемещается в начало программы, то ошибок, как и ожидалось, нет. Все связанные с областью вопросы решаются.

Если я попробую этот код в прогу.файл cpp , затем компилятор выдает ошибку для redeclaration. Это также ожидаемое поведение.

поэтому я заключаю, что это связано с компилятором gcc, делает ли любой флаг/параметры, которые используются для компиляции/построения результатов exe в этом поведении для компилятора gcc.

может ли rsp опубликовать данные файла make для дальнейшей проверки?