Sizeof (x ++) neden x değerini artırmıyor?


505

Dev c ++ pencerelerinde derlenen kod:

#include <stdio.h>

int main() {
    int x = 5;
    printf("%d and ", sizeof(x++)); // note 1
    printf("%d\n", x); // note 2
    return 0;
}

Not 1'ix uyguladıktan sonra 6 olmasını bekliyorum . Ancak, çıktı:

4 and 5

Herkes not 1x sonra neden artmıyor açıklayabilir ?


37
DevC ++ çok eski bir derleyici kullanıyor, yeni bir IDE'ye yükseltmek isteyebilirsiniz, örneğin Codeblocks Eclipse veya Visual Studio
Tom J Nowell

4
++ x, x ++, cygwin ve gcc 3.4.4 ile aynı sonucu verir.
yehnan

6
@Tim Pletzcker Çünkü ilk değer, değişkenin kendisi değil, değişkenin sizeof öğesidir.
Surfbutler

Cevabım bununla birleşme nedeniyle eklendi Cevabım aslında VLAsdiğerlerinin hiçbirinin çalışmadığı durumlarda çalışma zamanı değerlendirmesini nasıl alabileceğinizi gösteriyor .
Shafik Yaghmour

2
İstenmeyen yan etkilere neden olabileceğinden bu tür yazılardan kaçınılmalıdır. Sorunuz zaten onlardan biri.
user666412

Yanıtlar:


537

Gönderen C99 Standardı (vurgu bana ait)

6.5.3.4/2

Sizeof işleci, işleneninin boyutunu (bayt cinsinden) verir; bu, bir ifade veya parantezin adı olabilir. Boyut, işlenen türünden belirlenir. Sonuç bir tamsayıdır. İşlenen türü değişken uzunluklu dizi türü ise, işlenen değerlendirilir; aksi takdirde, işlenen değerlendirilmez ve sonuç bir tamsayı sabitidir.


51
"İşlenen türü değişken uzunluklu dizi türü ise, işlenen değerlendirilir" vay! Bunu hiç fark etmedim
Kos

6
değişken uzunluklu dizi türü ile ne demek istiyorsun? Bu işlenenin bir dizi olduğu anlamına mı geliyor? Bu durumda kod bir dizi değildir. Benim için bir şeyleri temizleyebilir misin?
Neigyl R.Noval

37
Değişken uzunluklu bir dizi, örneğin Nstdin'den okuyup yaparsanız, derleme sırasında boyutu bilinmeyen bir değer olarak bildirilen bir dizidir int array[N]. Bu, C ++ özelliklerinden biri olmayan C99 özelliklerinden biridir.
Kos

21
@LegendofCage, özellikle bu, sizeof(int[++x])(gerçekten, gerçekten kötü bir fikir, her neyse) gibi bir şeyde ++değerlendirilebileceği anlamına gelir.
Jens Gustedt

3
@Joe Wreschnig: Bu tarafından değerlendirilir gcc, clangve en ideone.com/Pf7iF
jfs

190

sizeofBir olan derleme zamanı operatörü böylece derleme zamanında, sizeofve işlenen sonucu değerine ile yer değiştirirler. İşlenen bir değerlendirilmedi hiç (bir değişken uzunluklu dizi hariç); sadece sonucun türü önemlidir.

short func(short x) {  // this function never gets called !!
   printf("%d", x);    // this print never happens
   return x;
}

int main() {
   printf("%d", sizeof(func(3))); // all that matters to sizeof is the 
                                  // return type of the function.
   return 0;
}

Çıktı:

2

olarak shortbenim makinemde 2 bayt kaplar.

İşlevin dönüş türünü şu şekilde değiştirmek double:

double func(short x) {
// rest all same

8çıktı olarak verecektir .


12
Sadece bazen - mümkünse derleme zamanı.
Martin Beckett

10
-1, çünkü bu kabul edilen (ve doğru) cevapla çelişmektedir ve standardı göstermemektedir.
sam hocevar

1
Dizelerle çalışırken sizeof () operatörünün zaman çözünürlüğünü derlemenin iyi bir yararı vardır. Dizgiyi içeren karakter dizisinin çalışma zamanında null sonlandırıcı için taranması gereken strlen () yerine tırnaklı dize olarak başlatılan bir dizeniz varsa, derleme zamanında sizeof (quoted_string) bilinir, ve bu nedenle çalışma zamanında. Bu küçük bir şeydir, ancak alıntılanan dizeyi milyonlarca ve milyonlarca kez kullanırsanız, performansta önemli bir fark yaratır.
user2548100

Bir döngüde milyonlarca ve milyonlarca kez gerçekten kullanırsanız, döngü hesaplamasının uzunluk hesaplamasını hesaba katmak çok daha mantıklı olmaz mıydı? Umarım kodunuzda milyonlarca ve milyonlarca farklı sabit kodlu sabit yoktur. : -o
Veky

47

sizeof(foo) derleme zamanında bir ifadenin boyutunu bulmak gerçekten çok çalışır:

6.5.3.4:

Sizeof işleci, işleneninin boyutunu (bayt cinsinden) verir; bu, bir ifade veya parantezin adı olabilir. Boyut, işlenen türünden belirlenir. Sonuç bir tamsayıdır. İşlenen türü değişken uzunluklu dizi türü ise, işlenen değerlendirilir; aksi takdirde, işlenen değerlendirilmez ve sonuç bir tamsayı sabitidir.

Kısacası: değişken uzunluklu diziler, çalışma zamanında çalıştırın. (Not: Değişken uzunluk Diziler - dizileri ile ayrılan bir spesifik bir özelliği vardır malloc(3)Aksi takdirde, sadece.) Tipi derleme zamanında ifade hesaplanır ve bu.


33

sizeofderleme zamanı yerleşik bir işleçtir ve bir işlev değildir . Parantez olmadan kullanabileceğiniz durumlarda bu çok açıktır:

(sizeof x)  //this also works

1
Ama bu sorunun cevabı nasıl?
Sebastian Mach

5
@phresnel: Bu sadece sizeof'in "garip" olduğunu ve normal işlev kurallarına tabi olmadığını açıkça belirtmek içindir. (+) Ve (-) gibi normal çalışma zamanı operatörleriyle olası karışıklığı kaldırmak için yayını yine de düzenledim
hugomg

sizeofOperatörüdür değil sadece bu anlamaya it a VLA vermek zorunda, bir derleme zamanı operatörü.
paxdiablo

21

Not

Bu cevap, geç tarihi açıklayan bir kopyadan birleştirildi.

orijinal

Değişken uzunluklu diziler hariç sizeof argümanlarını değerlendirmez. Biz taslak C99 standart bölümünden görebilirsiniz 6.5.3.4 sizeof operatörü paragraf 2 diyor ki:

Sizeof işleci, işleneninin boyutunu (bayt cinsinden) verir; bu, bir ifade veya parantezin adı olabilir. Boyut, işlenen türünden belirlenir. Sonuç bir tamsayıdır. İşlenen türü değişken uzunluklu dizi türü ise, işlenen değerlendirilir; aksi takdirde, işlenen değerlendirilmez ve sonuç bir tamsayı sabitidir.

Bir yorum ( şimdi kaldırıldı ), böyle bir şeyin çalışma zamanında değerlendirilip değerlendirilmeyeceğini sordu:

sizeof( char[x++]  ) ;

ve gerçekten de böyle bir şey işe yarayacaktır ( İkisini de canlı görün ):

sizeof( char[func()]  ) ;

çünkü ikisi de değişken uzunluklu dizilerdir. Her ikisinde de çok pratik kullanım görmüyorum.

Not, değişken uzunluklu diziler taslak C99 standart bölümünde 6.7.5.2 Dizi bildiricileri paragraf 4 kapsamındadır :

[...] Boyut bir tamsayı sabit ifadesiyse ve öğe türü bilinen bir sabit boyuta sahipse, dizi türü değişken uzunluklu bir dizi türü değildir; aksi takdirde, dizi türü değişken uzunluklu bir dizi türüdür.

Güncelleme

C11'de VLA vakası için cevap değişir, bazı durumlarda boyut ifadesinin değerlendirilip değerlendirilmediği belirtilmez. 6.7.6.2 Dizi bildiricileri bölümünden :

[...] Bir boyut ifadesinin bir sizeof operatörünün işlenmesinin bir parçası olduğu ve boyut ifadesinin değerinin değiştirilmesi operatörün sonucunu etkilemeyeceği durumlarda, boyut ifadesinin değerlendirilip değerlendirilmediği belirtilmez.

Örneğin böyle bir durumda ( canlı olarak görün ):

sizeof( int (*)[x++] )

1
Burada hatırlanması gereken önemli bir nokta, çoğu zaman sizeofetkili bir makrodur - kod oluşturmaz, ancak beklenen değeri önceden hesaplar ve doğrudan koda yatırır. VBA'lar olmadığı için bu C99'a kadar olan tek davranış olduğunu unutmayın (bu cevaba kadar onları gerçekten duymadım, ister inanın ister inanmayın!)
Corley Brigman

Her ikisi de bu işleç için normal olan ifadenin değerini ve yeni değerini belirlemek dışında herhangi bir şey sizeof (char[x++]);için değerini nasıl kullanırdı ? xx++x
supercat

@alk ... err, evet, tabii ki 'VLA' demek istedim :) Shafik - neden çalışma zamanında değerlendirilsin ki? Dediğim gibi, VLA'ları hiç görmedim, ama bunların her ikisi de derleme zamanında biliniyor, değil mi?
Corley Brigman

@CorleyBrigman çabuk cevap standart b / c olurdu, ama nedeni b / c biz derleme zamanında dizi boyutunu bilmiyoruz, bu yüzden çalışma zamanında ifade değerlendirmek zorundayız. VLA'lar ilginç bir konu, işte burada ve burada iki yazı var .
Shafik Yaghmour

@Shafik - ahh, tamam, sanırım karışıklığım char[x++]bir VLA olduğunu fark etmemiştim . char*tanınmayan gözlerime etkili bir şekilde benziyor .
Corley Brigman

11

sizeofOperatörün işleneni değerlendirilmediğinden, bunu yapabilirsiniz:

int f(); //no definition, which means we cannot call it

int main(void) {
        printf("%d", sizeof(f()) );  //no linker error
        return 0;
}

Çevrimiçi demo: http://ideone.com/S8e2Y

Diğer bir deyişle, yalnızca fkullanıldıysa işlevi tanımlamanız gerekmez sizeof. Bu teknik çoğunlukla C ++ şablon meta programlamasında kullanılır;sizeof değerlendirilmez.

Bu neden işe yarıyor? Çalışır çünkü sizeofoperatör değer üzerinde çalışmaz bunun yerine çalışır, tip ifadesinin. Bu nedenle, yazdığınızda sizeof(f()), ifadenin türü üzerinde çalışır f()ve işlevin dönüş türünden başka bir şey değildirf . İşlev, gerçekte yürütülürse hangi değeri döndürürse döndürsün her zaman aynıdır.

C ++ 'da bunu bile yapabilirsiniz:

struct A
{
  A(); //no definition, which means we cannot create instance!
  int f(); //no definition, which means we cannot call it
};

int main() {
        std::cout << sizeof(A().f())<< std::endl;
        return 0;
}

Yine de, sizeof ben ilk örneğini oluşturarak ediyorum, Ayazılı tarafından, A()işlevini çağırarak sonra ve fyazılı tarafından, örneğindeA().f() , ancak böyle bir şey oluyor.

Demo: http://ideone.com/egPMi

İşte diğer ilginç özelliklerini açıklayan başka bir konu sizeof:


10

Derleme sırasında yürütme yapılamaz. Yani ++i/ i++olmayacak. Ayrıca sizeof(foo())işlevi yürütmez, ancak doğru türü döndürür.


2
Derleme sırasında idam yapılamaz. ” Ne demek istiyorsun?
curiousguy

1
Derleme yalnızca nesne kodu oluşturur ... Nesne kodu yalnızca kullanıcı ikili dosyayı çalıştırdığında çalıştırılır. Sizeof derlendiğinde i ++ artışının yanlış olacağını varsayarsak.
rakesh

" Sizeof derleme zamanında olduğu gibi " demek: " sizeofderleme zamanı sabit bir ifade gibi"?
curiousguy

Ön işleme sırasında "#define" olduğu gibi, derleme zamanında da benzer şekilde gerçekleşir. Derleme sırasında tüm tür bilgileri kullanılabilir, böylece sizeof değerlendirilir ve orada derleme sırasında ve değer değiştirilir. @Pmg tarafından daha önce de belirtildiği gibi "C99 Standardından".
rakesh

1
değişken boy dizisi olmayan bir şey için " sizeof derleme zamanında gerçekleşecek "
curiousguy

0

sizeofderleme zamanında çalışır, ancak x++yalnızca çalışma zamanında değerlendirilebilir. Bunu çözmek için, C ++ standardı işleneninin sizeofdeğerlendirilmediğini belirtir . C Standardı diyor ki:

İşlenen [of sizeof] türü değişken uzunluklu bir dizi türü ise, işlenen değerlendirilir; aksi takdirde, işlenen değerlendirilmez ve sonuç bir tamsayı sabitidir.


C ++ 'da VLA yoktur.
LF

-2

sizeof() operatörü yalnızca veri türünün boyutunu verir, iç elemanları değerlendirmez.


Bu yanlıştır, sizeof()operatör özyinelemeli olarak hareket eder ve bir kabın tüm öğelerinin bayt cinsinden, bir sınıfın veya yapının üyelerinden vb. Boyut alır. Birkaç üyeli basit bir sınıf oluşturarak bunu kendinize kolayca kanıtlayabilirsiniz. çağırıyor sizeof(). (Ancak, orada herhangi bir işaretçi boyutunu göremezsiniz - sadece işaretçinin boyutu.) Bu, diğer yorumcuların belirttiği gibi, derleme zamanında gerçekleşir: içindeki ifadeler sizeof()değerlendirilmez.
Tyler Shellberg
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.