Nie mogę tego rozgryźć:
int main() {
int (*) (int *) = 5;
return 0;
}
Powyższe przypisanie kompiluje się z g ++ c ++ 11. Wiem, że int (*) (int *)
jest to wskaźnik do funkcji, która przyjmuje (int *)
argument jako argument i zwraca wartość int, ale nie rozumiem, jak można to zrównać do 5. Na początku myślałem, że jest to funkcja, która stale zwraca 5 (z mojej ostatniej nauki w F #, prawdopodobnie haha), wtedy pomyślałem krótko, że wskaźnik funkcji wskazuje na lokalizację pamięci 5, ale to oczywiście nie działa, podobnie jak wartości szesnastkowe.
Myśląc, że może to być spowodowane tym, że funkcja zwraca int, a przypisanie int jest w porządku (w jakiś sposób), spróbowałem też tego:
int * (*) (int *) = my_ptr
gdzie my_ptr
jest typu int *
, tego samego typu co ten drugi wskaźnik funkcji, tak jak w pierwszym przypadku typu int. To się nie kompiluje. Przypisanie 5 lub dowolnej wartości int zamiast tego my_ptr
również nie jest kompilowane dla tego wskaźnika funkcji.
Więc co oznacza to zadanie?
Zaktualizuj 1
Mamy potwierdzenie, że jest to błąd, jak pokazano w najlepszej odpowiedzi. Jednak nadal nie wiadomo, co tak naprawdę dzieje się z wartością przypisaną do wskaźnika funkcji lub co dzieje się z przypisaniem. Wszelkie (dobre) wyjaśnienia na ten temat będą bardzo mile widziane! Zapoznaj się z poniższymi zmianami, aby uzyskać więcej informacji na temat problemu.
Edytuj 1
Używam gcc w wersji 4.8.2 (w Ubuntu 4.8.2)
Edytuj 2
Właściwie zrównanie tego z czymkolwiek działa na moim kompilatorze. Nawet zrównanie go ze zmienną std :: string lub nazwą funkcji, która zwraca wartość double, działa.
Edytuj 2.1
Co ciekawe, uczynienie go wskaźnikiem funkcji do dowolnej funkcji, która zwraca typ danych, który nie jest wskaźnikiem, pozwoli na kompilację, na przykład
std::string (*) () = 5.6;
Ale gdy tylko wskaźnik funkcji znajdzie się na funkcji, która zwraca jakiś wskaźnik, nie kompiluje się, na przykład with
some_data_type ** (*) () = any_value;
źródło
error: expected identifier or '(' before ')' token
int *x = 5
tobą to nazwałeśx
. Dziękiint * (*x) (int *) = 5
temu nie będzie się kompilować. (aczkolwiek skompiluje się jako kod C).int(*) = 5;
iint(*);
Odpowiedzi:
To błąd w g ++.
int (*) (int *)
to nazwa typu.
W C ++ nie można mieć deklaracji z nazwą typu bez identyfikatora.
Więc to kompiluje się z g ++.
int (*) (int *) = 5;
i to również się kompiluje:
int (*) (int *);
ale obie są nieważnymi deklaracjami.
EDYCJA :
TC wspomina w komentarzach o bugzilli o błędzie 60680 z podobnym przypadkiem testowym,
ale nie został on jeszcze zatwierdzony. Błąd został potwierdzony w bugzilli.EDYCJA2 :
Gdy dwie powyższe deklaracje znajdują się w zakresie plików, g ++ poprawnie wysyła diagnostykę (nie wydaje diagnostyki w zakresie blokowym).
EDYCJA3 :
Sprawdziłem i mogę odtworzyć problem w najnowszej wersji g ++ w wersji 4 (4.9.2), najnowszej wersji przedpremierowej 5 (5.0.1 20150412) i najnowszej wersji eksperymentalnej 6 (6.0.0 20150412).
źródło
error C2059: syntax error : ')'
int (*int_func)(int *);
która deklaruje wskaźnik funkcji o nazwieint_func
.int x[5];
i nieint[5] x;
To nie jest poprawne C ++. Pamiętaj, że skoro Twój konkretny kompilator się kompiluje, nie oznacza to, że jest prawidłowy. Kompilatory, podobnie jak każde złożone oprogramowanie, czasami mają błędy, a ten wydaje się być jednym.
Natomiast
clang++
narzeka:funnycast.cpp:3:11: error: expected expression int (*) (int *) = 5; ^ funnycast.cpp:3:18: error: expected '(' for function-style cast or type construction int (*) (int *) = 5; ~~~ ^ funnycast.cpp:3:19: error: expected expression int (*) (int *) = 5; ^ 3 errors generated.
Jest to oczekiwane zachowanie, ponieważ naruszający wiersz nie jest prawidłowy w C ++. To rzekomo przypisanie (z powodu
=
), ale nie zawiera identyfikatora.źródło
Jak wskazywały inne odpowiedzi, jest to błąd
kompiluje. Rozsądnym przybliżeniem tego stwierdzenia, które powinno mieć znaczenie, jest:
Teraz
proc
jest wskaźnikiem do funkcji, która oczekuje adresu5
będzie adresem podstawowym funkcji, która przyjmujeint*
i zwracaint
.W niektórych mikrokontrolerach / mikroprocesorach
5
może być prawidłowy adres kodowy i może być tam możliwe zlokalizowanie takiej funkcji.Na większości komputerów ogólnego przeznaczenia pierwsza strona pamięci (adresy
0-1023
stron 4K) jest celowo nieważna (niezamapowana) w celu przechwytywanianull
dostępu przez wskaźnik.Tak więc, chociaż zachowanie zależy od platformy, można rozsądnie oczekiwać, że wystąpi błąd strony po
*proc
wywołaniu (np.(*proc)(&v)
.). Przed momentem*proc
wezwania nic niezwykłego się nie dzieje.O ile nie piszesz dynamicznego linkera, prawie na pewno nie powinieneś obliczać liczbowo adresów i przypisywać ich do zmiennych wskaźnikowych do funkcji.
źródło
/usr/lib/gcc/x86_64-pc-cygwin/4.9.2/cc1plus.exe -da so.cpp
Ta linia poleceń generuje wiele plików pośrednich. Pierwszy z nich
so.cpp.170r.expand
mówi:... int main() () { int D.2229; int _1; ;; basic block 2, loop depth 0 ;; pred: ENTRY _1 = 0; ;; succ: 3 ;; basic block 3, loop depth 0 ;; pred: 2 <L0>: return _1; ;; succ: EXIT } ...
To wciąż nie wyjaśnia, co się dokładnie dzieje, ale powinien to być krok we właściwym kierunku.
źródło