Dlaczego ten kod się kompiluje?
_Static uint32_t my_arr[2];
_Static_assert(sizeof(my_arr) == 8, "");
_Static_assert(sizeof(my_arr[0]) == 4, "");
_Static_assert(sizeof(my_arr)[0] == 4, "");
Pierwsze 2 potwierdzenia są oczywiście poprawne, ale spodziewałbym się, że ostatni wiersz zakończy się niepowodzeniem, ponieważ rozumiem, że sizeof()
powinien być przeliczany na literał całkowity, którego nie można traktować jako tablicy. Innymi słowy, zakończy się niepowodzeniem w taki sam sposób, jak następująca linia:
_Static_assert(4[0] == 4, "");
Co ciekawe, poniższe rzeczy rzeczywiście nie dają się skompilować (co powinno robić to samo, nie?):
_Static_assert(*sizeof(my_arr) == 4, "");
błąd: niepoprawny argument typu jednoargumentowego „*” (ma „long unsigned int”) _Static_assert (* sizeof (my_arr) == 4, „”);
Jeśli to ma znaczenie, używam gcc 5.3.0
( sizeof( my_arr ) )[ 0 ]
zawodzi.Odpowiedzi:
sizeof
nie jest funkcją. Jest to operator jednoargumentowy, taki jak!
lub~
.sizeof(my_arr)[0]
parses assizeof (my_arr)[0]
, co jest tylkosizeof my_arr[0]
z nadmiarowymi nawiasami.To jest tak samo jak
!(my_arr)[0]
parsowanie jako!(my_arr[0])
.Ogólnie rzecz biorąc, operatory przyrostkowe mają wyższy priorytet niż operatory przedrostkowe w C.
sizeof *a[i]++
parses assizeof (*((a[i])++))
(operatory przyrostkowe[]
i++
są stosowanea
najpierw do operatorów przedrostkowych*
isizeof
).(To jest wersja wyrażenia
sizeof
. Istnieje również wersja typu, która przyjmuje nazwę typu w nawiasachsizeof (TYPE)
:. W takim przypadku parametry byłyby wymagane i byłyby częściąsizeof
składni).źródło
sizeof
byciu jednoargumentowym operatorem."... parses as sizeof (my_arr[0])"
? Samo dodanie spacji tak naprawdę niczego nie zmienia.sizeof((my_array)[0])
zamiast tegosizeof
ma dwie „wersje”:sizeof(type name)
isizeof expression
. Ten pierwszy wymaga pary()
wokół argumentu. Ale ten drugi - ten z wyrażeniem jako argumentem - nie ma()
wokół swojego argumentu. Cokolwiek()
użyjesz w argumencie, jest postrzegane jako część wyrażenia argumentu, a nie częśćsizeof
samej składni.Ponieważ
my_arr
jest znany kompilatorowi jako nazwa obiektu, a nie nazwa typu,sizeof(my_arr)[0]
kompilator w rzeczywistości widzi twoją jakosizeof
zastosowaną do wyrażenia:,sizeof (my_arr)[0]
gdzie(my_arr)[0]
jest wyrażeniem argumentu.()
Otaczający nazwa tablicy jest czysto zbędne. Całe wyrażenie jest interpretowane jakosizeof my_arr[0]
. Jest to odpowiednik twojego poprzedniegosizeof(my_arr[0])
.(Oznacza to, przy okazji, że twój poprzedni
sizeof(my_arr[0])
zawiera również parę zbędnych()
.)Jest to dość rozpowszechnione nieporozumienie, że
sizeof
składnia w jakiś sposób wymaga par()
argumentów. To błędne przekonanie wprowadza w błąd intuicję ludzi podczas interpretowania takich wyrażeń, jaksizeof(my_arr)[0]
.źródło
int
nie jest prawidłowym wyrażeniem, więc nie można użyć druga forma z nim.[]
mają wyższą prekendencję niżsizeof
. Taksizeof(my_arr)[0]
samo jaksizeof((my_arr)[0])
.Oto link do tabeli pierwszeństwa.
źródło
Używasz wersji
sizeof
operatora, która przyjmuje wyrażenie jako parametr. W przeciwieństwie do tego, który przyjmuje typ, nie wymaga nawiasów. Stąd operand jest prosty(my_arr)[0]
, a nawiasy są zbędne.źródło