Sizeof (my_arr) [0] neden sizeof (my_arr [0]) 'ı derler ve eşittir?


129

Bu kod neden derleniyor?

_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, "");

İlk 2 iddia açıkça doğrudur, ancak son satırın başarısız olmasını beklerdim, çünkü benim anlayışım, sizeof()bir dizi olarak ele alınamayacak bir tamsayı değişmezi olarak değerlendirilmelidir. Başka bir deyişle, aşağıdaki satırın başarısız olmasıyla aynı şekilde başarısız olur:

_Static_assert(4[0] == 4, "");

İlginç bir şekilde, aşağıdakiler gerçekten derlenemez (hangisi aynı şeyi yapıyor olmalı, hayır?):

_Static_assert(*sizeof(my_arr) == 4, "");

hata: tekli '*' geçersiz tür bağımsız değişkeni ('uzun işaretsiz int' var) _Static_assert (* sizeof (my_arr) == 4, "");

Önemliyse gcc 5.3.0 kullanıyorum


15
( sizeof( my_arr ) )[ 0 ]Başarısız olduğundan şüpheleniyorum .
Andrew Henle

Yeni bir yinelenen bu sözdiziminde başka bir sürprizle karşılaşıyor: sizeof (x) ++ neden derleniyor?
Peter Cordes

Yanıtlar:


197

sizeofbir işlev değildir. !Veya gibi tekli bir operatör ~.

sizeof(my_arr)[0]Gereksiz parantezlerle sizeof (my_arr)[0]olduğu gibi ayrıştırır sizeof my_arr[0].

Bu, aynen !(my_arr)[0]ayrıştırmak gibidir !(my_arr[0]).

C Genel olarak, sonek operatörleri önek operatörler daha yüksek önceliğe sahip sizeof *a[i]++olarak ayrıştırmak sizeof (*((a[i])++))(sonek operatörleri []ve ++uygulanır a, sonra önek operatörler *ve sizeof).

(Bu, ifadesinin ifade sürümüdür sizeof. Ayrıca, parantezli bir tür adı alan bir tür sürümü vardır sizeof (TYPE):. Bu durumda, parenler gerekli ve sizeofsözdiziminin bir parçası olacaktır .)


14
Sizeof'un tekli bir operatör olduğunu ve bir fonksiyon olmadığını kesinlikle biliyordum, ama tamamen unuttum. Woops. Detaylı açıklama için teşekkürler. [] 'Nin *' dan daha yüksek önceliğe sahip olması gerçeği ne olursa olsun ilginçtir.
bgomberg

@melpomene İlginç. Tek sizeofoperatör olmayı hiç düşünmemiştim .
mutantkeyboard

5
Değil mi "... parses as sizeof (my_arr[0])"? Bir boşluk eklemek gerçekten hiçbir şeyi değiştirmez.
Bernhard Barker

Bunun sizeof((my_array)[0])yerine tavsiye ederim
bolov


46

sizeofiki "sürümü" vardır: sizeof(type name)ve sizeof expression. İlki (), argüman etrafında bir çift gerektirir . Ancak ikincisi - argüman olarak ifadeye sahip ()olan - argümanı etrafında yok . ()Bağımsız değişkende ne kullanırsanız kullanın, sizeofsözdiziminin bir parçası değil, bağımsız değişken ifadesinin bir parçası olarak görülür .

Yana my_arrbir nesne adı değil, bir tür adı olarak derleyiciye bilinir, senin sizeof(my_arr)[0]olduğu gibi aslında derleyici tarafından görülen sizeofbir ifadesi uygulanan: sizeof (my_arr)[0]nerede (my_arr)[0]argüman ifadesidir. ()Çevre dizi adı tamamen gereksizdir. Tüm ifade olarak yorumlanır sizeof my_arr[0]. Bu, öncekine eşdeğerdir sizeof(my_arr[0]).

(Bu, BTW, öncekinizin sizeof(my_arr[0])de bir çift gereksiz olduğu anlamına gelir ().)

sizeofSözdizimi bir şekilde ()argüman etrafında bir çift gerektiren oldukça yaygın bir yanlış anlamadır . Bu yanlış anlama, bu tür ifadeleri olarak yorumlarken insanların sezgilerini yanlış yönlendiren şeydir sizeof(my_arr)[0].


1
İlk sürüm, makinede genel olarak bir tamsayının boyutunu kontrol edebilmeniz için mevcuttur (64 bitlik makineler bile olmadığı zamanlardan!), Ancak intgeçerli bir ifade değildir, bu nedenle kullanamazsınız onunla ikinci form.
NH.

25

[]daha yüksek bir önceliğe sahip sizeof. Yani sizeof(my_arr)[0]aynıdır sizeof((my_arr)[0]).

İşte bir öncelik tablosunun bağlantısı.


8

sizeofParametre olarak bir ifade alan operatör sürümünü kullanıyorsunuz . Bir türü alır biri aksine, gelmez parantez gerektirir. Bu nedenle, (my_arr)[0]parantez gereksiz olduğu için işlenen basittir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.