Hmm, podejrzewam, że to coś, co nie zadziałałoby we wczesnych dniach C. Jest jednak sprytne.
Wykonując kroki pojedynczo:
&a
pobiera wskaźnik do obiektu typu int [5]
+1
pobiera następny taki obiekt, zakładając, że istnieje ich tablica
*
skutecznie konwertuje ten adres na wskaźnik typu do int
-a
odejmuje dwa wskaźniki int, zwracając liczbę int wystąpień między nimi.
Nie jestem pewien, czy jest to całkowicie legalne (mam na myśli język - prawnik prawniczy - nie sprawdzi się w praktyce), biorąc pod uwagę niektóre operacje tego typu. Na przykład „wolno” odejmować dwa wskaźniki tylko wtedy, gdy wskazują na elementy w tej samej tablicy. *(&a+1)
została zsyntetyzowana przez dostęp do innej tablicy, aczkolwiek tablicy nadrzędnej, więc w rzeczywistości nie jest wskaźnikiem do tej samej tablicy, co a
. Ponadto, chociaż możesz zsyntetyzować wskaźnik znajdujący się za ostatnim elementem tablicy i możesz traktować dowolny obiekt jako tablicę składającą się z 1 elementu, operacja wyłuskiwania ( *
) nie jest „dozwolona” na tym zsyntetyzowanym wskaźniku, mimo że nie zachowuje się w tym przypadku!
Podejrzewam, że we wczesnych dniach C (składnia K&R, ktoś?) Tablica rozpadała się na wskaźnik znacznie szybciej, więc *(&a+1)
może zwracać tylko adres następnego wskaźnika typu int **. Bardziej rygorystyczne definicje współczesnego C ++ zdecydowanie pozwalają na istnienie wskaźnika do typu tablicy i znajomość rozmiaru tablicy, i prawdopodobnie standardy C poszły w ich ślady. Cały kod funkcji C przyjmuje tylko wskaźniki jako argumenty, więc widoczna techniczna różnica jest minimalna. Ale ja tylko zgaduję.
Tego rodzaju szczegółowe pytanie dotyczące legalności zwykle dotyczy interpretera języka C lub narzędzia typu lint, a nie skompilowanego kodu. Interpreter może zaimplementować tablicę 2D jako tablicę wskaźników do tablic, ponieważ jest jedna funkcja mniej czasu wykonywania do zaimplementowania, w którym to przypadku dereferencja +1 byłaby fatalna, a nawet gdyby zadziałała, dałaby błędną odpowiedź.
Inną możliwą słabością może być to, że kompilator C może wyrównać zewnętrzną tablicę. Wyobraź sobie, że byłaby to tablica 5 znaków ( char arr[5]
), gdy program wykonuje &a+1
, wywołuje zachowanie „tablica tablicy”. Kompilator może zdecydować, że tablica zawierająca 5 znaków ( char arr[][5]
) jest w rzeczywistości generowana jako tablica zawierająca 8 znaków ( char arr[][8]
), tak aby zewnętrzna tablica była ładnie wyrównana. Kod, który omawiamy, zgłosiłby teraz rozmiar tablicy jako 8, a nie 5. Nie mówię, że konkretny kompilator na pewno by to zrobił, ale może.
&a + 1
nie wskazuje na żaden prawidłowy obiekt, więc jest nieprawidłowy.