Neden uzun bir int bazı makinelerde 12 bayt alıyor?


26

Bu kodu makinemde derledikten sonra garip bir şey farkettim:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");

    int a,b,c,d;

    int e,f,g;

    long int h;

    printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
        &a,&b,&c,&d,&e,&f,&g,&h);

    return 0;
}

Sonuç şudur. Her int adresi arasında 4 baytlık bir fark olduğuna dikkat edin. Ancak son int ile long int arasında 12 baytlık bir fark vardır:

 Hello, World!
 The addresses are:

 da54dcac 
 da54dca8 
 da54dca4 
 da54dca0 
 da54dc9c 
 da54dc98 
 da54dc94 
 da54dc88

3
Başka koy intsonra hkaynak kodunda. Derleyici daha önce boşluğa koyabilir h.
ctrl-alt-delor

32
Boyutu belirlemek için bellek adresleri arasındaki farkı kullanmayın. Bunun bir sizeofişlevi var. printf("size: %d ", sizeof(long));
Chris Schneider

10
Adreslerinizin yalnızca düşük 4 baytını yazdırıyorsunuz %x. Şanslısınız ki, beklediğiniz biçim dizgisine sahip işaretçi argümanlarını iletmek platformunuzda doğru bir şekilde çalışıyor unsigned int, ancak işaretçiler ve girişler birçok ABI'de farklı boyutlarda. %pİşaretçileri taşınabilir kodda yazdırmak için kullanın . (Kodunuzun, ilk 8 göstergenin üst / alt yarısına yazdırılacağı bir sistemi hayal etmek kolaydır. 8'in yarısı yerine 8)
Peter Cordes

5
@ SizeSt kullanarak yazdırmak için%zu chrisSchneider kullanın . @yoyo_fun adresleri yazdırmak için kullanın%p . Yanlış Biçim belirteci kullanarak çağırır tanımsız davranış
phuclv

2
@luu yanlış bilgiyi yaymaz. Hiçbir düzgün derleyici C'de değişkenlerin bildirilme sırasını umursamıyor. Eğer umursuyorsa, sizin tarif ettiğiniz şekilde yapmasının bir nedeni yoktur.
gnasher729

Yanıtlar:


81

12 bayt almadı, sadece 8 aldı. Ancak, bu platformda 8 bayt uzunluğunda bir int için varsayılan hizalama 8 bayttır. Dolayısıyla, derleyicinin uzun int'yi 8 ile bölünebilen bir adrese taşıması gerekiyordu. "Barut" adres olan da54dc8c, 8 byte bölü 12 bölü aralığına bölünemez.

Bunu test edebilmelisin. Eğer uzuntan önce başka bir int eklerseniz, bunlardan 8 tanesi vardır, uzun int'nin bir hamle olmadan tamam hizalı olacağını bulmalısınız. Şimdi önceki adresten sadece 8 bayt olacak.

Muhtemelen bu testin çalışması gerekmesine rağmen, bu şekilde organize edilen değişkenlere güvenmemelisiniz. AC derleyicisinin, yeniden sıralama değişkenleri (bazı uyarılarla birlikte) dahil olmak üzere programınızın hızlı bir şekilde çalışmasını sağlamak için her türlü korkak şeyi yapmasına izin verilir.


3
fark, boşluk değil.
Deduplicator

10
msgstr "yeniden sıralama değişkenleri dahil". Derleyici, aynı anda iki değişken kullanmamaya karar verirse, aynı zamanda kısmen üst üste bindirmek veya tamamen üst üste binmek ücretsizdir ...
Roger Lipscombe

8
Ya da gerçekten, onları yığının yerine kayıtlara koyun.
Monica'ya Zarar Vermeyi Durdurun

11
@OrangeDog Adres bu durumda olduğu gibi alınırsa bunun olacağını sanmıyorum ama genel olarak elbette haklısınız.
Alex

5
@Alex: Adres alırken hafıza ve kayıtlarla komik şeyler elde edebilirsiniz. Adresi almak, ona bir hafıza yeri vermek zorunda olduğu anlamına gelir, ancak onu kullanmak zorunda olduğu anlamına gelmez. Adresi alırsanız, ona 3 atayın ve başka bir işleve geçirirseniz, RDI'ye 3 yazıp araştırabilir, asla belleğe yazmaz. Bazen bir hata ayıklayıcıda şaşırtıcı.
Zan Lynx

9

Bunun nedeni, derleyicinizin bellekte doğru şekilde hizalandığından emin olmak için değişkenler arasında fazladan boşluk oluşturmasıdır.

Çoğu modern işlemcide, bir değerin boyutunun katı olan bir adresi varsa, erişmek daha verimli olur. O koymuştu hilk kullanılabilir noktada bulunmaktadır adresi 8'in bir katı değil, bu yüzden kullanımı az verimli olurdu ki, 0xda54dc8c olurdu. Derleyici bunu biliyor ve gerçekleşmesini sağlamak için son iki değişkeniniz arasında kullanılmayan bir boşluk ekliyor.


Açıklama için teşekkürler. Boyutlarından katları olan değişkenlere erişimin daha etkili olmasının nedenleri ile ilgili bazı malzemeleri bana gösterebilir misiniz? Bunun neden olduğunu bilmek istiyorum.
yoyo_fun

4
eğer @yoyo_fun ve gerçekten bellek anlamak istiyorum, o zaman konu üzerinde ünlü bir kağıt var futuretech.blinkenlights.nl/misc/cpumemory.pdf
Alex

1
@ yoyo_fun Çok basit. Bazı bellek denetleyicileri yalnızca işlemcinin bit genişliğinin katlarına erişebilir (örn. 32 bit işlemci yalnızca doğrudan 0-3, 4-7, 8-11, vb. Adresleri isteyebilir). Hizalanmamış bir adres isterseniz, işlemcinin iki bellek isteği yapması ve ardından verileri kayıt defterine koyması gerekir. Öyleyse, 32-bit'e geri dönersek, adres 1'de saklanan bir değer istiyorsanız, işlemcinin 0-3, 4-7 adreslerini istemesi, ardından 1, 2, 3 ve 4'ten baytları alması gerekir. Hafızanın boşa harcanması.
phyrfox 12:17

2
Küçük nokta, ancak yanlış hizalanmış hafıza erişimi, performans vuruşu yerine kurtarılamaz bir hata olabilir. Mimariye bağımlı.
Jon Chesterfield

1
@JonChesterfield - Evet. Bu yüzden verdiğim tarifnamenin çoğu modern mimariye (özellikle de x86 ve ARM demek istediğim) uygulandığını açıkladım . Farklı şekillerde davranan başkaları da var, ancak bunlar daha az yaygın. (İlginç: ARM kullanılan erişim hizalanmış gerekli mimarileri biri olduğu, ancak daha sonra gözden geçirilmesinde hizalanmamış erişim otomatik işleme eklendi)
Jules

2

Testiniz mutlaka ne olduğunu düşündüğünüzü test etmez, çünkü dilin bu yerel değişkenlerin herhangi birinin adresini birbiriyle ilişkilendirmesine gerek yoktur.

Depolama dağılımı hakkında bir şey çıkartabilmek için bunları bir yapıya koymak zorunda kalacaksınız.

Yerel değişkenlerin yan yana depolamayı belirli bir şekilde paylaşması gerekmez. Derleyici istifin herhangi bir yerinde, örneğin bu yerel değişkenlerin ikisinin arasında olabilecek geçici bir değişken ekleyebilir.

Aksine, bir yapıya geçici bir değişken eklemenize izin verilmez, bu nedenle yapı alanlarının adreslerini yazdırırsanız, aynı mantıksal bellek aynasından (yapı) tahsis edilen öğeleri karşılaştırırsınız.

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.