2013-08-15 28 views
6

NajwyraźniejDlaczego można zadeklarować struct i non-struct o tej samej nazwie?

Z powodów, które docierają do prehistorii C, możliwe jest, aby zadeklarować struct i non-struct o tej samej nazwie w tym samym zakresie. - (Bjarne Stroustrup - C++ Programming Language 4th Edition.)

Na przykład:

struct Ambig {}; 

// the struct must be referred to with the prefix struct 
void Ambig(struct Ambig* buf) {} 

Jestem tylko ciekaw, co początkowy powodem było? Bez zrozumienia wydaje się, że jest to przykład złego projektu językowego, który powoduje niejednoznaczność i jest mylący.

+0

Być może właśnie to prowadzi do potrzeby przedkładania 'struct'. Czy możesz wskazać źródło swojego cytatu? –

+0

@KarthikT Bjarne Stroustrup - Język programowania C++ 4. wydanie – Oleksiy

+3

Istnieje mnóstwo sposobów na spowodowanie semantycznej dwuznaczności i zamieszania, obowiązek unikania tych kłamstw z programistą, a nie z projektantem języka. Nie ma wieloznaczności składniowej, ponieważ prefix 'struct' sugerowałby, że mówimy o' struct'. – Dukeling

Odpowiedz

6

Powodem, o którym mowa w cytacie z Stroustrup, jest historyczne. W języku C, musisz musi zawsze prefiksować nazwę struktury z struct; nazwa struktury (jak nazwa związków lub wyliczeń) jest nazywana znacznikiem i żyje w zupełnie innej nazwie niż inne symbole. A więc rzeczy takie jak:

struct stat 
{ 
    // ... 
}; 
int stat(char const* filename, struct stat* buf); 

są całkowicie legalne. (Powyższe jest w rzeczywistości częścią Posix).

W C++, nazwa klasy (zadeklarowanego przy class, struct lub union) lub enum jest w tej samej przestrzeni nazw, jak wszystko inne, i w przeciwieństwie do C, można napisać takie rzeczy jak:

struct MyClass {}; 
MyClass variableName; 

nie byłoby to legalne C. W C, druga linia musiałaby być:

struct MyClass variableName; 

Problemem jest to, że C++ wymaga, aby móc korzystać z interfejsów zdefiniowane w C (podobnie jak interfejs Posix, powyżej). Więc C++ definiuje kilka specjalnych reguł, aby na to pozwolić: możesz podać zmienną lub funkcję, a typ klasy taką samą. Gdy to zrobisz, zmienna lub funkcja nazwa ma pierwszeństwo, i ukrywa nazwę klasy , z wyjątkiem „opracowanego typu specyfikatorami” (tj class, struct, union lub enum, a następnie symbol), gdzie nazwy non-type są ignorowane podczas wyszukiwania.

1

Cóż, dodając struct przed structs jest całkowicie legalne C. Dlatego niektóre C kod dotyczy również C++.
Czego się spodziewałeś? C++ bazuje na C.

W języku C++ unikamy używania struct przed każdą strukturą. Nigdy nie widziałem tego w kodzie produkcyjnym.

Jeśli chodzi o niejednoznaczność, nie sądzę, by ktokolwiek wiedział, dlaczego na to pozwolił. Ale uważam, że jest tak, ponieważ niejednoznaczność została rozwiązana po dodaniu struct. Zasadniczo mówisz kompilatorowi, że nie jest to funkcja i dlatego wyeliminowano possible meaning.

+0

Dzięki za odpowiedź! Przepraszam, co masz na myśli mówiąc "unikamy używania struct przed każdą strukturą"? – Oleksiy

+1

@Oleksiy po prostu oznacza, że ​​C++ kompilatory są wystarczająco inteligentny, aby wiedzieć, masz na myśli struct tak poprzedzając go słowem kluczowym „struktury” nie jest konieczne – greatwolf

+1

Istnieje kilka problemów z tym odpowiedź. Pierwsze polega na systematycznym używaniu słowa kluczowego "struct", gdy nazwa typu jest zaangażowana nie tylko w języku C, ale jest wymagana. Interfejsy C (takie jak Posix) _do_ mają funkcje i struktury o tej samej nazwie, więc są przypadki, w których musisz to zrobić w C++. To jest prawdziwy powód, dla którego jest to dozwolone. –

3

Powodem jest to jak ma to związek z C++ dziedziczenie z C. nie został „dodany” do C++, to jest tam, bo to działa w ten sposób w C

W C, trzeba użyć struct X i union Y (nie ma słowa kluczowego class w języku C) lub użyj typedef struct X A;, a następnie użyj nazwy A zamiast strcut X (gdzie X i A mogą być takie same).

W języku C++ kompilator będzie, o ile nazwa jest unikatowa, rozumieć, że X odnosi się do struct X. Nie musisz wpisywać przed nazwą nazwy: struct, union lub class lub użyć typedef, aby utworzyć nową, samodzielną nazwę.

Ponieważ C++ został zaprojektowany, aby umożliwić (w miarę możliwości) użycie składni C, nadal można pisać struct X, odnosząc się do struktury. Pozwala to na użycie nazwy, która poza tym jest niejednoznaczna.

Zaleca się, aby nie skorzystać z tej „możliwości”, chyba że wymagane przez historycznych decyzji projektowych, ponieważ wszystko to osiągnąć jest bardziej zamieszanie ...

+0

Witam, to nie było tak naprawdę moje pytanie - wiem, że opcjonalne jest użycie struct przed nazwą. Ale dzięki za wysiłek, jestem pewien, że niektórzy ludzie uznają to za pomocne! – Oleksiy

+0

Ponownie ostatnie zdanie, nie zawsze masz wybór. Posix definiuje 'struct stat' i funkcję' stat() '(która przyjmuje" struct stat * "jako swój drugi argument). Jeśli chcesz użyć tej funkcji, musisz mieć gdzieś 'struct stat'. –

+0

Edytowałem w pierwszym akapicie, aby wyjaśnić, DLACZEGO tak jest. –

2

Jestem tylko ciekaw, co początkowy powód był? Bez zrozumienia wydaje się, że jest to przykład złego projektu językowego, który powoduje niejednoznaczność i jest mylący.

W języku C jest to pierwsza implementacja przestrzeni nazw. Identyfikatory żyją w różnych przestrzeniach nazw i myślą, że mogą mieć tę samą nazwę, jeśli są zadeklarowane w różnych przestrzeniach nazw. Nazwa przestrzeń dla znaczników struktury i zwykłych identyfikatorów nie są tylko dwa miejsca w nazwa C w C są cztery miejsca Nazwa:

(C99, 6.2.3 miejsca Nazwisko identyfikatorów P1) „Tak, istnieją osobne przestrzenie nazw dla różnych kategorii identyfikatorów, co następuje:

- Nazwy etykiet (ujednoznacznione przez składni deklaracji etykiet i wykorzystywania);

- The tagi struktur, związków i wyliczeń (ujednoznacznione wykonując any24) z kluczowymi struct, unia, czy wyliczenia);

- członków struktur lub związków; każda struktura czy Unia ma osobną nazwę przestrzeń dla jego członkowie (disambiguated przez typ wyrażenie używane do uzyskania dostępu do członka za pośrednictwem operatora. lub ->

- wszystkie inne identyfikatory, zwane zwykłymi identyfikatorami (zadeklarowane w zwykłych deklaratorach lub jako stałe wyliczeniowe). "

+0

Przynajmniej w najwcześniejszych wersjach C (i myślę, że nawet dzisiaj), istnieje dokładnie jedna przestrzeń nazw dla wszystkich członków struct i wsp., A nazwy członków różnych struktur nie mogą być w konflikcie. To dlatego członkowie większości struktur tradycyjnie zaczynają od prefiksu; na przykład w 'struct tm' masz' tm_year', a nie tylko 'year'. –

+0

@JamesKanze Przynajmniej nie w Standard C jako * każda struktura lub związek ma ** oddzielną przestrzeń nazw ** dla swoich członków *. – ouah

+1

Co ma sens. Ale nie było tak w K & R I. I pamiętam, że wyłapałem błędy z powodu 'C * cp; /*...*/ cp-> memberOfD; 'Nie tylko brak błędu, ale nawet ostrzeżenia (chyba że użyłeś' lint'). –