Переменная с тем же именем, что и тип, не выдает ошибки компиляции при размещении в функции, структуре или классе

#c #gcc #visual-c #typedef

Вопрос:

Учитывая код:

 #include <iostream>

typedef int Integer;
Integer Integer = 1234;

int main() {
    std::cout <<  "Integer: " << Integer;
}
 

Компиляция кода с помощью компилятора gcc 11.2 приведет к ошибкам компиляции:

 error: 'Integer Integer' redeclared as different kind of entity
    4 | Integer Integer = 1234;
      |         ^~~~~~~

note: previous declaration 'typedef int Integer'
    3 | typedef int Integer;
      |             ^~~~~~~

In function 'int main()':
error: expected primary-expression before ';' token
    7 |         std::cout <<  "Integer: " << Integer;
      |                                             ^
 

Однако изменение кода на:

 #include <iostream>

typedef int Integer;

int main() {
    Integer Integer = 1234;
    std::cout <<  "Integer: " << Integer;
}
 

не приведет к ошибке компиляции.
Я попытался использовать компилятор
gcc 11.2
,
clang 12.0.1
и MSVC 19.29, и все они потерпели неудачу в первой версии, но разрешили вторую.
Почему вторая версия работает, в то время как первая выходит из строя?

Комментарии:

1. Полностью оставляя в стороне вопрос, является ли это ошибкой компилятора или является ли что-либо из этого допустимым на C : зачем кому-то вообще это нужно? Внутри или вне функции?

2. Я бы никогда не написал ничего подобного. Однако сегодня я столкнулся с этой проблемой в компании, в которой в настоящее время работаю. Кто-то назвал свою переменную так же, как и ее тип, и, хотя она работала в функции, она не была объявлена в глобальной области видимости.

3. ::Integer отличается от переменной, объявленной и определенной внутри main .

4. это «буффало буффало буффало..» садовая дорожка, выполненная способом C … только роли предложений в C определяются областями действия.

Ответ №1:

Разница заключается в области охвата.

В первом примере оба Integer s объявлены в глобальной области:

 typedef int Integer;
Integer Integer = 1234;
 

Во втором примере один объявлен в глобальной области, в то время как другой является локальным для main :

 typedef int Integer;
int main() {
    Integer Integer = 1234;
    ...
}
 

Это работает, потому что в тот момент , когда компилятор читает первый Integer внутри main , существует только одна сущность с таким именем, поэтому она должна ссылаться на тип в глобальной области. Но как только вы объявили переменную с именем Integer внутри main , вы не сможете использовать это имя снова для ссылки на тип вместо этого:

 typedef int Integer;
int main() {
    Integer Integer = 1234; // OK because only the type is visible.
    Integer otherInteger = 567; // Error because Integer is a variable here.
    ::Integer thirdInteger = 89; // OK because :: resolves to the global one.
}