No dobra, trochę lakonicznie się wypowiedziałem wcześniej - ale poprawnie. Ten kod to UB, i de facto w tym momencie powinna kończyć się jego analiza.
Niemniej jednak można poczynić pewne założenia co się dzieje w Twoim przypadku.
Założenia:
-
tab
jest poprawnie zalignowane z short
- Masz system oparty na little-endian (wedle niektórych "uporządkowanie grubokońcówkowe" :D)
- Kompilator nie korzysta ze strict aliasingu (
-fno-strict-aliasing
)
- Ten kod nie zawiera UB ;)
- Bajt = 8 bitów
-
sizeof(short)
= sizeof(char) * 2
W tym momencie weźmy pod uwagę pierwsze sześć wartości z tablicy tab
(pozostałe nie mają znaczenia):
0,1,2,3,4,0
tab
jest wskaźnikiem (w uproszczeniu) na początek tablicy. Wskazuje więc na pierwsze zero:
0,1,2,3,4,0
^^
Rzutujesz teraz ten wskaźnik na short
(btw, to jest nielegalne rzutowanie w C++ - musisz rzutować jawnie), a on dalej wskazuje na tę samą lokację w pamięci, ale jako short:
0,1,2,3,4,0
^^^^
Wskazujesz więc na liczby 0, 1. Teraz, wiedząc, że bajt ma 8 bitów, są to kolejno 000000002 i 000000012, a wiedząc, że używamy kolejności cyfr little endian (czyli odwrotnie niż ludzie), dwubajtowa wartość short
jest rozumiana jako 00000001000000002, czyli 25610
Teraz wróćmy do arytmetyki wskaźników: w C jest to jedna z nielicznych rzeczy, w których język idzie "na rękę" programiście. Inkrementacja lub dodanie wartości do wskaźnika zwiększa bezwzględną wartość komórki pamięci o wielkość typu, na który wskazuje. Więc tab+1
wskaże na adres o 1 bajt dalej, a wsk+1
wskaże na adres o 2 bajty dalej (pod warunkiem, że założenia wyżej są prawdziwe):
tab+1
:
0,1,2,3,4,0
^^
wsk+1
:
0,1,2,3,4,0
^^^^
Wobec tego, wsk += 2
oznacza, że wsk
wskazuje na piąty i szósty bajt tablicy tab
:
0,1,2,3,4,0
^^^^
Analogicznie do poprzedniego przypadku, 4 i 0 to kolejno 000001002 i 000000002, czyli jako short
00000000000001002, czyli 410