2017-12-12 135 views
21

Chociaż patrząc na niektóre kodu C++ 03, znalazłem wystąpienie najbardziej irytującej parse że mylić mnie:Najbardziej dokuczliwy parse z dostępem do tablicy

#include <sstream> 
#include <string> 

int main(int, char** argv) 
{ 
    std::stringstream ss(std::string(argv[0])); 
} 

live example on wandbox

we fragmencie powyżej , ss jest deklaracją funkcji, która pobiera std::string* i zwraca std::stringstream.

W jaki sposób std::string(argv[0]) jest analizowany jako std::string*?

Intuicyjnie pomyślałem, że argv[0] był jednoznacznie dostęp do argv.

+0

To nie dla mnie kompilacji z Visual Studio 2015, ponieważ 'argv [0]' jest najwyraźniej 0 rozmiarów tablica typu 'argv'. Mogę uzyskać taki sam wynik jak ty, jeśli użyję 'argv [1]'. Interesujące pytanie. –

+4

Myślę, że jest to odpowiednik 'std :: stringstream ss (std :: string argv []);' który sam jest równoważny 'std :: stringstream ss (std :: string * argv);'. –

+0

Myślę, że była ta jedna wskazówka, jeśli wygląda na to, że jest to jedna. tak jak @ FrançoisAndrieux napisał twoją instancję z std :: string nie jest instancją, ale deklaracją dla tablicy std: stringów – ExOfDe

Odpowiedz

18

Powodem jest to, ponieważ w kontekście deklaracji funkcji, kompilator zinterpretuje std::string(argv[0]) jako std::string argv[0], czyli deklaracji o zerowej wielkości tablicy jako parametr funkcji nazwieargv(przysłania argv z main, ponieważ jest to inny zakres), który następnie jest równoważny wskaźnikowi od matrycy do rozpadu wskaźnika.

Dlatego std::stringstream ss(std::string(argv[0])); oznacza to samo co std::stringstream ss(std::string* argv);

EDIT: Jak został poprawnie annotaded w komentarzach, deklaracji tablicy zerowej wielkości są nieważne w C++, czyniąc program źle sformułowane. Podczas kompilowania tego kodu z flagami -pedantic (GCC i clang) będą wysyłane ostrzeżenia. Program Visual Studio powoduje nawet błąd kompilacji. W przypadku każdego innego indeksu tablicy niż 0, powyższa argumentacja nadal pozostaje.

+1

, więc najbardziej irytująca parse jest jeszcze bardziej zła niż zawsze myślałem ...nie jest tylko "jeśli wygląda jak deklaracja funkcji, jest deklaracją funkcji", ale także "jeśli wygląda na nieprawidłową deklarację funkcji, jest deklaracją funkcji" ... omfg – user463035818

+2

@ tobi303: Zerknij na gramatykę . Definiuje tablice z grubsza jako 'typ nazwa_opcjonalna [size_expression]' i nie ma specjalnej reguły gramatycznej dla wyrażeń, które oceniają na zero. Byłoby to jednak trudne, ponieważ ocena ekspresji w C++ to Turing-complete. – MSalters

+1

@ tobi303 to jednak nie jest nieprawidłowa deklaracja. W C++, [deklaracja zmiennej może zawijać nazwę zmiennej w nawiasach] (https://stackoverflow.com/questions/29675601/). Tj. Int (x) 'jest takie samo jak' int x'. Dlatego 'std :: string (argv [0])' może być postrzegany jako 'std :: string argv [0]' w tym kontekście. Po prostu usuń 'std :: string', aby uniknąć MVP:' std :: stringstream ss (argv [0]); ' –

7

Wierzę, że wynika to ze "składni deklaracji jest jak składnia wyrażeń" i faktu, że parametry "tablicy" są wskaźnikami.

następujących zgłoszeń tablicy są równoważne

int x[1]; 
int (x)[1]; 
int (x[1]); 

bardziej lub mniej, ponieważ x[a], (x)[a] i (x[a]) równorzędne wyrażenia.

Zatem

std::stringstream ss(std::string(argv[0])) 

       <=> 

std::stringstream ss(std::string argv[0]) 

       <=> 

std::stringstream ss(std::string* argv)