2013-08-09 41 views
6

Nie jestem w stanie zrozumieć, dlaczego to nie działa.Porządek "statycznej" definicji i "zewnętrznej deklaracji" w jednostce tłumaczeniowej

extern int i; 

int main() 
{ 
    printf(" %d ", i); 
} 

static int i =3; 

Również to nie działa:

extern int i; 

static int i =3; 

int main() 
{ 
    printf(" %d ", i); 
} 

Ale jeśli static zmienna jest zdefiniowana przed extern declaration to działa:

static int i =3; 

extern int i; 

int main() 
{ 
    printf(" %d ", i); 
} 

Jak rozumiem z extern int i mówi, że jest i obecny gdzieś indziej i tutaj jak to wygląda (int i)

Ale gdzieś indziej środki:

1) Może później punkt w jednostce same translacji jako global variable.

2) Może, w niektórych jednostkach translacyjnych other.

Myślałem, że (1) będzie ważny, mimo że static int i = 3 ograniczył zakres i do bieżącej jednostki tłumaczeniowej, w której jest zdefiniowany.

Czy nie jest to static int i =3global (mam na myśli przynajmniej to, że jest widoczny w jednostce tłumaczeniowej), mimo że ma ograniczony zakres do swojej jednostki tłumaczeniowej? Dlaczego więc kompilator nie może go znaleźć?

Kiedy skompilować dwie pierwsze wersje pojawia się następujący błąd kompilacji czas:

error: static declaration of ‘i’ follows non-static declaration 
note: previous declaration of ‘i’ was here 

Jestem w stanie zrozumieć ten komunikat o błędzie. Ponadto, dlaczego narzeka na to jako statyczne declaration czy nie jest to również definition?

+0

Co dokładnie "nie działa"? Czy to jest problem z kompilacją? Problem z uruchomieniem? Kompiluję kod za pomocą VS 2010 i wygląda na to, że działa poprawnie. – Nbr44

+0

Kombinator GCC, otrzymuję komunikat o błędzie czasu kompilacji statycznej deklaracji i podąża za deklaracją niestatyczną. –

Odpowiedz

6

C11 6.2.2 Powiązania identyfikatorów Sekcja 4

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

Więc druga deklaracja pójdą pierwsze, z powrotem do swoich przykładach 1 i 2 przykład i będzie miał extern pamięci masowej klasy. Kompilator uważa, że ​​to błąd.

Podczas gdy w trzecim przykładzie, i będzie static, ponieważ static pokazuje pierwszy. To nie powinno być problemu.

Oraz w sekcji 7 C11 6.2.2 Powiązania identyfikatorów

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

Więc lepiej nie zadeklarować taką samą zmienną zarówno static i extern w tej samej jednostce tłumaczeniowej.

+0

Tak, zgadzam się. Ale co mnie martwi, to dlaczego wersja '3''' always' działa? W wielu kompilatorach. –

+0

@UchiaItachi: Dlaczego martwisz się trzecią wersją? Ta odpowiedź cytuje tekst ze standardu C, który wyjaśnia to: Kiedy deklaracja "extern" następuje po deklaracji z wewnętrznym ("statycznym") lub zewnętrznym powiązaniem, używana jest poprzednia deklaracja. –

+0

@UchiaItachi Po pierwsze, nawet jeśli przetestowałeś wszystkie kompilatory, których wyraźnie nie możesz i wszystko działa, nie oznacza to, że jest to zdefiniowane zachowanie. Standardem jest ten, który decyduje. –

2

Cóż, zmienną jest extern lub static. Pamiętaj, że static na poziomie globalnym ogranicza widoczność tylko do bieżącej jednostki tłumaczeniowej, natomiast extern wskazuje, że jest ona widoczna dla różnych jednostek tłumaczeniowych.

+0

Wiem, że 'statyczny' unieważnia widoczność, a' zewnętrzny' może oznaczać inne jednostki tłumaczeniowe włącznie z bieżącym. Ale kod działa, jeśli zdefiniuję wcześniej zmienną statyczną i podam deklarację zewnętrzną, potwierdzającą, że ma ona "static" i "extern". –

+0

To naprawdę naprawdę mnie zaskoczyło, ale moim jedynym wytłumaczeniem jest sam komunikat o błędzie: "statyczna deklaracja" i "wynika z deklaracji niestatycznej". Jak rozumiem, "static" musi poprzedzać każdą deklarację niestatyczną. A do czasu, gdy 'extern' jest osiągnięty, istnieje już definicja' i', z której zadowolony jest 'extern'. – Nobilis

0

Nie ma sensu zadeklarować czegoś jako static i ponownie jako extern. Jest to niezdefiniowane zachowanie, więc nie rób tego.

+0

Ale dlaczego nie istnieje deklaracja "zewnętrzna"? Aby powiedzieć, że jest zdefiniowany w dalszej części pliku? I wiem, że twój kod działa tak, jak już wspomniałem w moim pytaniu. –

+0

@UchiaItachi, zredagowałem moją odpowiedź, jest poprawna. To niezdefiniowane zachowanie. –