Değerleri ne olursa olsun türler neden daima belirli bir boyuttadır?


149

Uygulamalar gerçek tür boyutları arasında farklılık gösterebilir, ancak çoğu durumda imzasız int ve float gibi türler her zaman 4 bayttır. Ama bir tür değeri ne olursa olsun neden her zaman belirli bir miktarda bellek kaplar ? Örneğin, 255 değeriyle aşağıdaki tamsayıyı oluşturduysam

int myInt = 255;

Sonra myIntderleyici ile 4 bayt işgal. Ancak, gerçek değer, 255sadece 1 bayt ile temsil edilebilir, neden myIntsadece 1 bayt bellek işgal etmiyor? Veya daha genel bir soru sorma: Bir değeri, değeri temsil etmek için gereken alan bu boyuttan daha küçük olabiliyorsa, neden bir türün kendisiyle ilişkilendirilmiş yalnızca bir boyutu vardır?


15
1) " Ancak gerçek değer, 256 sadece 1 bayt ile temsil edilebilir " Yanlış, en büyük unsingeddeğer, 1 bayt ile temsil edilebilir 255. 2) Değer değiştikçe, bir değişkenin en uygun depolama boyutunu hesaplama ve depolama alanını daraltma / genişletme yükünü göz önünde bulundurun.
Algirdas Preidžius

99
Peki, hafızadaki değeri okuma zamanı geldiğinde , makinenin kaç bayt okunacağını nasıl belirleyeceğini nasıl öneriyorsunuz? Makine değeri okumayı nerede durduracağını nasıl bilecek? Bu, ek tesisler gerektirecektir. Ve genel olarak, bu ek tesisler için bellek ve performans yükü, unsigned intdeğer için sabit 4 bayt kullanılması durumundan çok daha yüksek olacaktır .
AnT

74
Bu soruyu gerçekten seviyorum. Cevaplamak kolay görünse de, kesin bir açıklama yapmanın bilgisayarların ve bilgisayar mimarilerinin gerçekte nasıl çalıştığını iyi bir şekilde anlamasını gerektirdiğini düşünüyorum. Çoğu kişi, kapsamlı bir açıklama yapmadan muhtemelen bunu sadece kabul edecek.
andreee

37
Değişkenin değerine 1 ekleyerek 256 olmasını sağlayarak ne olacağını düşünün, böylece genişlemesi gerekir. Nereye genişliyor? Yer açmak için kalan hafızayı hareket ettiriyor musunuz? Değişkenin kendisi hareket ediyor mu? Varsa, nereye taşınır ve güncellemeniz gereken işaretçileri nasıl bulursunuz?
molbdnilo

13
@someidiot hayır, yanılıyorsun. std::vector<X>her zaman aynı boyuta sahiptir, yani sizeof(std::vector<X>)derleme zamanı sabitidir.
SergeyA

Yanıtlar:


131

Derleyicinin bazı makine için birleştirici (ve sonuçta makine kodu) üretmesi beklenir ve genellikle C ++ bu makineye sempatik olmaya çalışır.

Alttaki makineye sempatik olmak kabaca anlamına gelir: makinenin hızlı bir şekilde gerçekleştirebileceği işlemlere verimli bir şekilde eşlenecek C ++ kodunun yazılmasını kolaylaştırır. Bu nedenle, donanım platformumuzda hızlı ve "doğal" veri türlerine ve işlemlerine erişim sağlamak istiyoruz.

Somut olarak, belirli bir makine mimarisini düşünün. Şu anki Intel x86 ailesini ele alalım.

Intel® 64 ve IA-32 Mimarlar Yazılım Geliştirici Kılavuzu cilt 1 ( bağlantı ), bölüm 3.4.1 şöyle diyor:

32 bit genel amaçlı kayıt EAX, EBX, ECX, EDX, ESI, EDI, EBP ve ESP, aşağıdaki öğeleri tutmak için sağlanmıştır:

• Mantıksal ve aritmetik işlemler için işlenenler

• Adres hesaplamaları için işlenenler

• Bellek İşaretçileri

Bu nedenle, derleyicinin basit C ++ tamsayı aritmetiğini derlediğinde bu EAX, EBX vb. Kayıtlarını kullanmasını istiyoruz. Bu, bir ilan ettiğimde int, bu kayıtlarla uyumlu bir şey olması gerektiği anlamına gelir , böylece onları verimli bir şekilde kullanabilirim.

Kayıtlar her zaman aynı boyuttadır (burada, 32 bit), bu yüzden benim int değişkenlerim de her zaman 32 bit olacaktır. Aynı düzeni (little-endian) kullanacağım, böylece bir kayda bir değişken değeri her yüklediğimde veya bir değişkeni bir kayıtta sakladığımda bir dönüşüm yapmak zorunda kalmam.

Godbolt'u kullanarak derleyicinin bazı önemsiz kodlar için tam olarak ne yaptığını görebiliriz:

int square(int num) {
    return num * num;
}

(GCC 8.1 ve -fomit-frame-pointer -O3basitlik için) aşağıdakileri derler :

square(int):
  imul edi, edi
  mov eax, edi
  ret

bu şu anlama gelir:

  1. int numparametresi tam olarak boyutu olduğu anlamına kayıt EDI geçirilen ve Intel yerli kayıt için bekliyoruz düzeni edildi. İşlevin hiçbir şeyi dönüştürmesi gerekmez
  2. çarpma imulçok hızlı olan tek bir komuttur ( )
  3. sonucun geri döndürülmesi sadece başka bir kayıt defterine kopyalanması meselesidir (arayan sonuç EAX'a konulmasını bekler)

Düzenleme: Biz bir yerli olmayan düzeni kullanarak fark göstermek için ilgili bir karşılaştırma ekleyebilirsiniz. En basit durum değerleri yerel genişlik dışında bir şeyde saklamaktır.

Godbolt'u tekrar kullanarak , basit bir yerel çarpmayı karşılaştırabiliriz

unsigned mult (unsigned x, unsigned y)
{
    return x*y;
}

mult(unsigned int, unsigned int):
  mov eax, edi
  imul eax, esi
  ret

standart olmayan bir genişlik için eşdeğer kodla

struct pair {
    unsigned x : 31;
    unsigned y : 31;
};

unsigned mult (pair p)
{
    return p.x*p.y;
}

mult(pair):
  mov eax, edi
  shr rdi, 32
  and eax, 2147483647
  and edi, 2147483647
  imul eax, edi
  ret

Tüm ekstra talimatlar, giriş biçimini (iki adet 31 bit işaretsiz tam sayı) işlemcinin doğal olarak işleyebileceği biçime dönüştürmeyle ilgilidir. Sonucu tekrar 31 bit değerine depolamak istersek, bunu yapmak için bir veya iki talimat daha olurdu.

Bu ekstra karmaşıklık, yalnızca yer tasarrufu çok önemli olduğunda bununla uğraşacağınız anlamına gelir. Bu durumda , daha basit bir kod oluşturacak olan yerel unsignedveya uint32_ttürü kullanmaya kıyasla yalnızca iki bit kaydediyoruz.


Dinamik boyutlar hakkında bir not:

Yukarıdaki örnek, değişken genişlik yerine sabit genişlikli değerlerdir, ancak genişlik (ve hizalama) artık yerel kayıtlarla eşleşmemektedir.

X86 platformu, ana 32-bit'e ek olarak 8-bit ve 16-bit de dahil olmak üzere çeşitli yerel boyutlara sahiptir (64 bit modundan ve basitlik için çeşitli diğer şeylerden bahsediyorum).

Bu tip (char, int8_t, uint8_t, int16_t vs) , aynı zamanda , doğrudan mimarisi ile desteklenen - kısmen eski 8086/286 / 386 / vs için geriye dönük uyumluluk. vb talimat setleri.

Kesinlikle en küçük doğal sabit boyutu seçmenin tipin iyi bir uygulama olabileceği kesinlikle doğrudur - hala hızlıdırlar, tek talimatlar yüklenir ve saklanır, yine de tam hızlı doğal aritmetik elde edersiniz ve hatta performansı artırabilirsiniz. önbellek isabetlerini azaltır.

Bu, değişken uzunluklu kodlamadan çok farklı - bunlardan bazılarıyla çalıştım ve korkunçlar. Her yük tek bir komut yerine bir döngü haline gelir. Her mağaza da bir döngü. Her yapı değişken uzunluktadır, bu nedenle dizileri doğal olarak kullanamazsınız.


Verimlilik hakkında bir not

Sonraki yorumlarda, depolama boyutuyla ilgili olarak anlayabildiğim kadarıyla "verimli" kelimesini kullanıyorsunuz. Bazen depolama boyutunu en aza indirmeyi seçeriz - dosyalara çok sayıda değer kaydederken veya bunları ağ üzerinden gönderirken önemli olabilir. Takas, onlarla herhangi bir şey yapmak için bu değerleri kayıtlara yüklememiz gerektiğidir ve dönüşümü gerçekleştirmek ücretsiz değildir.

Verimliliği tartıştığımızda, neyi optimize ettiğimizi ve takasların ne olduğunu bilmemiz gerekir. Yerel olmayan depolama türlerini kullanmak, alan için işlem hızını değiştirmenin bir yoludur ve bazen mantıklıdır. Değişken uzunlukta depolama kullanarak (en azından aritmetik tipler için), daha az yer kazanmak için daha fazla işlem hızı (ve kod karmaşıklığı ve geliştirici süresi) kullanır.

Bunun için ödediğiniz hız cezası, yalnızca bant genişliğini veya uzun süreli depolamayı kesinlikle en aza indirmeniz gerektiğinde faydalıdır ve bu durumlarda genellikle basit ve doğal bir biçim kullanmak daha kolaydır - ve daha sonra genel amaçlı bir sistemle sıkıştırın (zip, gzip, bzip2, xy ya da her neyse).


tl; Dr.

Her platformun bir mimarisi vardır, ancak verileri temsil etmek için esasen sınırsız sayıda farklı yolla gelebilirsiniz. Herhangi bir dil için sınırsız sayıda yerleşik veri türü sağlamak makul değildir. Bu nedenle, C ++, platformun doğal, doğal veri türleri kümesine örtülü erişim sağlar ve diğer (yerel olmayan) gösterimleri kendiniz kodlamanıza olanak tanır.


Hepsini anlamak için çalışırken tüm güzel cevaplara bakıyorum .. Yani cevabınızla ilgili olarak, dinamik bir boyut olmaz, bir tamsayı için 32 bitten az, sadece bir kayıtta daha fazla değişkene izin vermez ? Endianess aynıysa, bu neden optimal olmaz?
Nichlas Uden

7
@asd ama şu anda bir kayıtta kaç değişken saklandığını belirten kodda kaç kayıt kullanacaksınız?
user253751

1
FWIW, yerden tasarruf etmenin, paketleme ve ambalajın açılma hızından daha önemli olduğuna karar verdiğinizde, mümkün olan en küçük alana birden fazla değer eklemek yaygındır. İşlemcilerin yerleşik kayıtları dışında herhangi bir şeyde doğru bir şekilde nasıl aritmetik yapılacağını bilmediği için genellikle paketlenmiş formlarında doğal olarak çalışamazsınız. İşlemci desteğiyle kısmi istisna için BCD'yi arayın
Useless

3
Aslında Eğer do bazı değerleri için 32 bite ihtiyaç, hala şimdi ben ihtiyaç uzunluğu depolamak için bir yere ihtiyacı fazla , bazı durumlarda 32 bit.
Yararsız

1
+1. "Basit ve doğal biçim ve sonra sıkıştır" tipik olarak daha iyi bir not: Bu kesinlikle genel olarak doğrudur , ancak : bazı veriler için VLQ-her bir değer-sonra-tüm-sıkıştır-her şey sadece sıkıştırmaktan daha iyi performans gösterir -Bütün-şey ve bazı uygulamalar için, veri sıkıştırılmış edilemez birlikte o da farklı (olduğu gibi, çünkü gitmeta veri 'ler) ya da aslında bir arada rastgele erişim için gereken bellekte tutarak ya da birkaç değiştirmek değil çoğunun edilir değerleri (HTML + CSS oluşturma motorlarında olduğu gibi) içerir ve bu nedenle yalnızca VLQ gibi bir şey kullanılarak yerinde durabilir.
mtraceur

139

Türler temel olarak depolamayı temsil ettiğinden ve geçerli değer değil, alabilecekleri maksimum değer olarak tanımlandığından .

Çok basit benzetme bir ev olurdu - bir evin içinde kaç kişi yaşadığına bakılmaksızın sabit bir boyutu vardır ve ayrıca belirli bir büyüklükteki bir evde yaşayabilecek maksimum insan sayısını belirleyen bir bina kodu da vardır.

Bununla birlikte, tek bir kişi 10 kişilik bir evde yaşıyor olsa bile, evin büyüklüğü mevcut kişi sayısından etkilenmeyecektir.


31
Benzetmeyi seviyorum. Biraz uzatırsak, türler için sabit bellek boyutları kullanmayan ve kullanılmadığı zamanlarda evimizdeki odaları devirmeye ve gerektiğinde bunları yeniden inşa etmeye benzer bir programlama dili kullandığımızı hayal edebiliriz. (yani, bir sürü ev inşa edip ihtiyaç duyduğumuzda onları bırakabileceğimiz zaman havai tonlar).
ahouse101

5
"
Türler

56
@ corvus_192 etiketinin anlamı var. Bu soru C ++ ile etiketlenmiştir, 'daktilo' ile değil
SergeyA

4
@ ahouse101 Gerçekten, sınırsız hassasiyetli tamsayılara sahip bir dizi dil var, gerektiğinde büyüyorlar. Bu diller değişkenler için sabit bellek ayırmanızı gerektirmez, bunlar dahili olarak nesne referansları olarak uygulanır. Örnekler: Lisp, Python.
Barmar

2
@jamesqf MP aritmetiğinin ilk olarak Lisp'de benimsenmesi, aynı zamanda otomatik bellek yönetimi yapması bir mantık değildir. Tasarımcılar performans etkilerinin programlama kolaylığına ikincil olduğunu hissettiler. Ve etkiyi en aza indirmek için optimizasyon teknikleri geliştirildi.
Barmar

44

Bir optimizasyon ve basitleştirme.

Sabit boyutlu nesneleriniz olabilir. Böylece değeri depolamak.
Veya değişken boyutlu nesneleriniz olabilir. Ama değer ve büyüklük depolamak.

sabit boyutlu nesneler

Numarayı işleyen kodun boyut hakkında endişelenmesine gerek yoktur. Her zaman 4 bayt kullandığınızı ve kodu çok basitleştirdiğinizi varsayarsınız.

Dinamik boyutlu nesneler

Bir değişkeni okurken, manipüle edilen sayının, değeri ve boyutu okuması gerektiğini anlaması gerekir. Kayıttaki tüm yüksek bitlerin sıfır olduğundan emin olmak için boyutu kullanın.

Değer geçerli boyutunu aşmamışsa, değeri belleğe geri yerleştirdiğinizde, değeri tekrar belleğe yerleştirin. Ancak değer küçülürse veya büyürse, taşmadığından emin olmak için nesnenin depolama konumunu bellekteki başka bir konuma taşımanız gerekir. Şimdi bu sayının konumunu izlemelisiniz (boyutu için çok büyürse hareket edebileceğinden). Potansiyel olarak tekrar kullanılabilmeleri için kullanılmayan tüm değişken konumlarını da izlemeniz gerekir.

özet

Sabit boyutlu nesneler için oluşturulan kod çok daha basittir.

Not

Sıkıştırma 255'in bir bayta sığacağı gerçeğini kullanır. Farklı numaralar için aktif olarak farklı boyut değerleri kullanacak olan büyük veri setlerini saklamak için sıkıştırma şemaları vardır. Ancak bu canlı veriler olmadığı için yukarıda açıklanan karmaşıklıklarınız yoktur. Verileri depolama için sıkıştırma / sıkıştırmayı kaldırma pahasına depolamak için daha az yer kullanırsınız.


4
Bu benim için en iyi cevap: Boyutu nasıl takip ediyorsunuz? Daha fazla bellek mi?
çevrimiçi Thomas

@ThomasMoors Evet, kesinlikle: daha fazla bellekle. Örneğin, dinamik bir diziniz varsa, bazıları into dizideki öğelerin sayısını depolar. Bu intyine sabit bir boyuta sahip olacak.
Alfe

1
@ThomasMoors, her ikisi de ekstra bellek gerektiren yaygın olarak kullanılan iki seçenek vardır - ya size ne kadar veri olduğunu söyleyen (sabit boyutlu) bir alanınız vardır (örneğin, dizi boyutu için bir int veya ilk olarak "pascal tarzı" dizeler) öğesi kaç karakter bulunduğunu içerir) veya alternatif olarak, her öğenin bir sonuncusu olup olmadığını bir şekilde not ettiği bir zincir (veya daha karmaşık bir yapıya sahip olabilirsiniz) (örneğin, sıfır sonlu dizeler veya bağlantılı listelerin çoğu biçimi).
Peteris

27

Çünkü C ++ gibi bir dilde, bir tasarım amacı basit işlemlerin basit makine talimatlarına derlenmesidir.

Tüm ana CPU komut setleri sabit genişlikli tiplerle çalışır ve değişken genişlikli tipler yapmak istiyorsanız, bunları işlemek için birden fazla makine talimatı yapmanız gerekir.

Temeldeki bilgisayar donanımının neden böyle olduğuna gelince : Bunun nedeni, çoğu vaka için daha basit ve daha verimli olmasıdır (hepsi değil).

Bilgisayarı bir bant parçası olarak düşünün:

| xx | xx | xx | xx | xx | xx | xx | xx | xx | xx | xx | xx | xx | ...

Bilgisayardan banttaki ilk bayta bakmasını söylerseniz, xxtürün orada durup durmadığını veya bir sonraki bayta ilerleyip ilerlemediğini nasıl bilebilir? Gibi bir ifade varsa 255(onaltılık FF) ya da benzeri bir numara 65535(onaltılık FFFF) ilk bayt her zaman FF.

Peki nasıl biliyorsun? Ek mantık eklemeniz ve değerin bir sonraki bayta devam ettiğini göstermek için en az bir bit veya bayt değerinin anlamını "aşırı yüklemeniz" gerekir. Bu mantık asla "özgür" değildir, ya yazılımda öykünürsünüz ya da bunu yapmak için CPU'ya bir grup ek transistör eklersiniz.

C ve C ++ gibi sabit genişlikli dil türleri bunu yansıtır.

O değil varBu şekilde ve maksimum verimli koda eşleme ile daha az ilgili olan daha soyut diller, sayısal türler için değişken genişlikli kodlamaları ("Değişken Uzunluk Miktarları" veya VLQ olarak da bilinir) kullanmakta serbesttir.

Daha fazla okuma: Eğer "değişken uzunlukta miktar" için arama Eğer kodlama bu tür durumlarda bazı örnekler bulabilirsiniz olduğu aslında verimli ve değer ilave mantık. Genellikle geniş bir aralıkta herhangi bir yerde olabilecek büyük miktarda değer depolamanız gerektiğinde, ancak çoğu değer küçük bir alt aralığa eğilimlidir.


Bir derleyici, herhangi bir kodu kırmadan değeri daha küçük bir alanda saklamaktan kurtulabileceğini kanıtlayabilirse (örneğin, yalnızca tek bir çeviri biriminde dahili olarak görünen bir değişkendir) ve optimizasyon sezgisel yönteminin Hedef donanımda daha verimli olacak , kodun geri kalanı standart bir şey yapmış gibi "çalıştığı sürece, buna göre optimize edilmesine ve daha küçük bir alanda saklanmasına tamamen izin verilir .

Ancak , kodun ayrı olarak derlenebilecek diğer kodlarla etkileşime girmesi gerektiğinde, boyutların tutarlı kalması veya her kod parçasının aynı kurala uygun olmasını sağlaması gerekir.

Çünkü tutarlı değilse, bu komplikasyon var: Peki ya da int x = 255;daha sonra yaptığım kodda ne olacak x = y? Eğer intdeğişken genişlikli olabilir, derleyici öncesinde bu gerekir maksimum alan miktarını önceden tahsis süresinin bilmek gerekir. Bu her zaman mümkün değildir, çünkü ybağımsız olarak derlenen başka bir kod parçasından bir argüman aktarılırsa ne olur ?


26

Java, tam olarak bunu yapmak için "BigInteger" ve "BigDecimal" adlı sınıfları kullanır, tıpkı C ++ 'ın GMP C ++ sınıf arayüzü gibi görünüyor (Digital Trauma sayesinde). İsterseniz hemen hemen her dilde kolayca kendiniz yapabilirsiniz.

CPU'lar her zaman herhangi bir uzunluktaki işlemleri desteklemek için tasarlanmış BCD'yi (İkili Kodlu Ondalık) kullanma yeteneğine sahiptir (ancak günümüzün GPU standartlarına göre YAVAŞ olacak bir seferde bir bayt üzerinde manuel olarak çalışma eğilimindesiniz).

Bunları veya diğer benzer çözümleri kullanmamamızın nedeni? Verim. En yüksek performanslı dilleriniz, bazı sıkı döngü işlemlerinin ortasında bir değişkeni genişletmeyi göze alamaz - çok belirleyici olmaz.

Yığın depolama ve taşıma durumlarında, paketlenmiş değerler genellikle SADECE kullanacağınız değer türüdür. Örneğin, bilgisayarınıza aktarılan bir müzik / video paketi, bir sonraki değerin boyut optimizasyonu olarak 2 bayt mı yoksa 4 bayt mı olduğunu belirtmek için biraz zaman harcayabilir.

Bir kez bilgisayarınızda olsa da, nerede kullanılabilir bellek ucuz ama yeniden boyutlandırılabilir değişkenlerin hızı ve komplikasyon değil .. bu gerçekten tek nedenidir.


4
Birinin BigInteger'den bahsettiğine sevindim. Bu aptalca bir fikir değil, sadece çok büyük sayılar için bunu yapmak mantıklı.
Max Barraclough

1
Bilgiçlik taslamak için aslında son derece hassas sayılar demek istersiniz :) En azından BigDecimal durumunda ...
Bill K

2
Ve bu c ++ olarak etiketlendiğinden , muhtemelen Java'nın Big * ile aynı fikir olan GMP C ++ sınıf arayüzünden bahsetmeye değer .
Dijital Travma

20

Çünkü dinamik boyutlara sahip basit tiplere sahip olmak çok karmaşık ve yoğun bir hesaplama olurdu. Bunun mümkün olabileceğinden emin değilim.
Bilgisayar, değerinin her değişikliğinden sonra sayının kaç bit aldığını kontrol etmelidir. Oldukça fazla ek operasyon olurdu. Derleme sırasında değişkenlerin büyüklüğünü bilmediğinizde hesaplamalar yapmak çok daha zor olurdu.

Değişkenlerin dinamik boyutlarını desteklemek için, bilgisayarın aslında bir değişkenin şu anda kaç bayt olduğunu hatırlaması gerekir ki bu da ... bu bilgiyi saklamak için ek bellek gerektirir. Doğru işlemci talimatını seçmek için değişken üzerindeki her işlemden önce bu bilgilerin analiz edilmesi gerekir.

Bilgisayarın nasıl çalıştığını ve değişkenlerin neden sabit boyutlara sahip olduğunu daha iyi anlamak için birleştirici dilinin temellerini öğrenin.

Her ne kadar, bence constexpr değerleri ile böyle bir şey elde etmek mümkün olacaktır. Ancak, bu, bir programcı için kodu daha az öngörülebilir hale getirir. Bazı derleyici optimizasyonlarının böyle bir şey yapabileceğini düşünüyorum, ancak işleri basit tutmak için bir programcıdan gizliyorlar.

Burada sadece bir programın performansıyla ilgili sorunları anlattım. Değişkenlerin boyutlarını azaltarak bellek tasarrufu yapmak için çözülmesi gereken tüm sorunları atladım. Dürüst olmak gerekirse, bunun bile mümkün olduğunu düşünmüyorum.


Sonuç olarak, beyan edilenden daha küçük değişkenlerin kullanılması sadece değerleri derleme sırasında biliniyorsa anlamlıdır. Modern derleyicilerin bunu yapması oldukça olasıdır. Diğer durumlarda çok fazla zor hatta çözülemeyen soruna neden olur.


Derleme zamanında böyle bir şey yapıldığından şüpheliyim. Derleyici belleğini bu şekilde korumanın pek bir anlamı yoktur ve tek faydası budur.
Bartek Banachewicz

1
Daha çok constexpr değişkenini normal değişkenle çarpmak gibi işlemleri düşünüyordum. Örneğin (teorik olarak) 8 baytlık constexpr değişkenimiz var 56ve bunu 2 baytlık bir değişkenle çarpıyoruz . Bazı mimarilerde 64 bit işlem daha fazla hesaplama ağırlığına neden olur, bu nedenle derleyici bunu yalnızca 16 bit çoğaltma yapmak için optimize edebilir.
NO_NAME

SNOBOL ailesindeki bazı APL uygulamaları ve bazı diller (SPITBOL Sanırım? Belki Simge) tam olarak bunu yaptı (ayrıntı düzeyi ile): gerçek değerlere bağlı olarak temsil biçimini dinamik olarak değiştirin. APL, Boolean'dan tamsayıya kayar ve geri döner. SPITBOL, Boolean'ların (bir bayt dizisinde depolanan 8 ayrı Boolean dizisi) sütun gösterimlerinden tamsayılara (IIRC) gider.
davidbak

16

Sonra myIntderleyici ile 4 bayt işgal. Ancak, gerçek değer, 255sadece 1 bayt ile temsil edilebilir, neden myIntsadece 1 bayt bellek işgal etmiyor?

Bu değişken uzunluklu kodlama olarak bilinir , örneğin VLQ gibi çeşitli kodlamalar tanımlanır . Bununla birlikte, en ünlülerden biri muhtemelen UTF-8'dir : UTF-8, 1'den 4'e kadar değişken sayıda bayt üzerindeki kod noktalarını kodlar.

Veya daha genel bir soru sorma: Bir değeri, değeri temsil etmek için gereken alan bu boyuttan daha küçük olabiliyorsa, neden bir türün kendisiyle ilişkilendirilmiş tek bir boyutu vardır?

Her zaman mühendislikte olduğu gibi, her şey değiş tokuş ile ilgilidir. Sadece avantajları olan bir çözüm yoktur, bu nedenle çözümünüzü tasarlarken avantajları ve değişimleri dengelemeniz gerekir.

Yerleştirilen tasarım, sabit boyutlu temel türleri kullanmaktı ve donanım / diller oradan uçtu.

Peki, değişken kodlamanın temel zayıflığı nedir, bu da belleğe daha fazla açlık şeması lehine reddedilmesine neden oldu? Rastgele Adresleme Yok .

UTF-8 dizesinde 4. kod noktasının başladığı bayt dizini nedir?

Önceki kod noktalarının değerlerine bağlıdır, doğrusal bir tarama gereklidir.

Şüphesiz rastgele adreslemede daha iyi olan değişken uzunlukta kodlama şemaları vardır?

Evet, ama aynı zamanda daha karmaşık. İdeal olan varsa, daha önce hiç görmedim.

Rastgele Adresleme gerçekten de önemli mi?

Oh evet!

Mesele şu ki, her türlü toplama / dizi sabit boyutlu türlere dayanır:

  • A? Nın 3. alanına erişiliyor struct? Rastgele Adresleme!
  • Bir dizinin 3. öğesine erişiliyor mu? Rastgele Adresleme!

Bu, aslında aşağıdaki değiş tokuş yaptığınız anlamına gelir:

Sabit boyut türleri VEYA Doğrusal bellek taramaları


Bu, ortaya çıkardığınız kadar sorun değil. Her zaman vektör tablolarını kullanabilirsiniz. Bir bellek yükü ve ekstra bir getirme var, ancak doğrusal taramalar gerekli değil.
Artelius

2
@Artelius: Tamsayılar değişken genişliğe sahip olduğunda vektör tablosunu nasıl kodlarsınız? Ayrıca, bellekte 1 ila 4 bayt kullanan tamsayılar için bir kodlama yaparken vektör tablosunun bellek yükü nedir?
Matthieu M.

Bakın, haklısınız, OP'nin verdiği belirli örnekte, vektör tablolarını kullanmanın avantajı sıfır. Bir vektör tablosu oluşturmak yerine, verileri bir dizi sabit boyutlu öğeye koyabilirsiniz. Ancak, OP daha genel bir cevap da istedi. Python'da, tamsayılar dizisi olan değişken büyüklükte tamsayılar vektör tablosu! Yani çözer çünkü değil bu sorunu ancak Python liste elemanları tüm elbette farklı boyutları vardır Tamsayılar, Şamandıralar, dicts, Dizeler veya Listeler, olacak mı derleme sırasında bilmediği için.
2018 tarihli Artelius

@Artelius: Python'da dizinin öğelere sabit boyutlu işaretçiler içerdiğini unutmayın ; bu, bir elemanın dolaylı maliyete ulaşmasını O (1) yapar.
Matthieu

16

Bilgisayar belleği, belirli bir boyuttaki (genellikle 8 bitlik ve bayt olarak adlandırılan) ardışık olarak adreslenen parçalara bölünür ve çoğu bilgisayar, ardışık adreslere sahip bayt dizilerine verimli bir şekilde erişmek için tasarlanmıştır.

Bir nesnenin adresi hiçbir zaman nesnenin ömrü içinde değişmezse, adresi verilen kod söz konusu nesneye hızlı bir şekilde erişebilir. Bununla birlikte, bu yaklaşımla ilgili önemli bir sınırlama, X adresi için bir adres atanırsa ve sonra Y adresi için N bayt uzakta başka bir adres atanırsa, X'in yaşam süresi içinde N bayttan daha büyük büyüyemeyeceği şeklindedir. X veya Y hareket ettirilmezse Y'nin. X'in hareket edebilmesi için, X'in adresini tutan evrendeki her şeyin yenisini yansıtacak şekilde güncellenmesi ve benzer şekilde Y'nin hareket etmesi gerekir. Bu tür güncellemeleri kolaylaştırmak için bir sistem tasarlamak mümkün olsa da (hem Java hem de .NET bunu oldukça iyi yönetir), ömürleri boyunca aynı konumda kalacak nesnelerle çalışmak çok daha verimlidir,


"X veya Y hareket ettirilmediği sürece X, Y ömrü boyunca N bayttan daha büyük büyüyemez. X'in hareket edebilmesi için, X'in adresini tutan evrendeki her şeyin yansıtacak şekilde güncellenmesi gerekir. yenisini ve aynı şekilde Y'nin hareket etmesini sağladı. " Bu göze çarpan nokta IMO: sadece mevcut değer ihtiyaçları kadar boyut kullanan nesneler, boyutlar / sentinler, bellek taşıma, referans grafikler vb. İçin tonlarca ek yük eklemelidir . ... ama yine de, özellikle de az sayıda kişinin yaptığı gibi, açıkça belirtmeye değer.
underscore_d

@underscore_d: Javascript gibi değişken boyutlu nesnelerle başa çıkmak için tasarlanmış diller inanılmaz derecede etkili olabilir. Öte yandan, değişken boyutlu nesne sistemlerini basitleştirmek ve bunları hızlı hale getirmek mümkün olmakla birlikte, basit uygulamalar yavaştır ve hızlı uygulamalar son derece karmaşıktır.
Supercat

13

Kısa cevap: Çünkü C ++ standardı böyle söylüyor.

Uzun cevap: Bir bilgisayarda yapabilecekleriniz nihayetinde donanım ile sınırlıdır. Tabii ki, bir tamsayıyı depolama için değişken sayıda bayta kodlamak mümkündür, ancak daha sonra okumak için performans için özel CPU talimatları gerekir veya bunu yazılımda uygulayabilirsiniz, ancak o zaman çok yavaş olacaktır. Önceden tanımlanmış genişliklerin değerlerini yüklemek için CPU'da sabit boyutlu işlemler mevcuttur, değişken genişlikler için hiçbiri yoktur.

Dikkate alınması gereken bir başka nokta da bilgisayar belleğinin nasıl çalıştığıdır. Diyelim ki tamsayı türünüz 1 ila 4 bayt depolama alanı kaplayabilir. 42 değerini tamsayıya kaydettiğinizi varsayalım: 1 bayt sürüyor ve X bellek adresine yerleştiriyorsunuz. Sonra bir sonraki değişkeni X + 1 konumunda saklıyorsunuz (bu noktada hizalamayı düşünmüyorum) vb. . Daha sonra değerinizi 6424 olarak değiştirmeye karar verdiniz.

Ama bu tek bir bayta uymuyor! Ee ne yapıyorsun? Gerisini nereye koyarsın? Zaten X + 1'de bir şey var, bu yüzden oraya yerleştiremezsiniz. Başka bir yer? Daha sonra nerede olduğunu nasıl bileceksin? Bilgisayar belleği ekleme semantiğini desteklemez: sadece bir yere bir şey yerleştiremez ve yer açmak için her şeyi bir kenara itemezsiniz!

Kenara: Bahsettiğiniz şey gerçekten veri sıkıştırma alanı. Sıkıştırma algoritmaları her şeyi daha sıkı paketlemek için var, bu yüzden en azından bazıları tamsayı için ihtiyaç duyduğundan daha fazla alan kullanmamayı düşünecek. Ancak, sıkıştırılmış verilerin değiştirilmesi kolay değildir (mümkünse) ve her değişiklik yaptığınızda yeniden sıkıştırılır.


11

Bunu yapmak oldukça önemli çalışma zamanı performans faydaları vardır. Değişken boyut türlerinde çalışacaksanız, işlemi yapmadan önce her bir sayının kodunu çözmeniz gerekir (makine kodu talimatları genellikle sabit genişliktir), işlemi yapın, ardından belleği tutacak kadar büyük bir boşluk bulun. Bunlar çok zor operasyonlar. Tüm verileri biraz verimsiz bir şekilde saklamak çok daha kolaydır.

Bu her zaman böyle yapılmaz. Google'ın Protobuf protokolünü düşünün. Protobuflar, verileri çok verimli bir şekilde iletecek şekilde tasarlanmıştır. Aktarılan bayt sayısının azaltılması, veriler üzerinde çalışırken ek talimatların maliyetine değer. Buna göre, protobuflar 1, 2, 3, 4 veya 5 bayttaki tam sayıları kodlayan bir kodlama kullanır ve daha küçük tamsayılar daha az bayt alır. Bununla birlikte, mesaj alındıktan sonra, kullanımı daha kolay olan daha geleneksel bir sabit boyutlu tamsayı biçimine açılır. Sadece ağ aktarımı sırasında bu kadar yer tasarrufu sağlayan değişken uzunluklu bir tamsayı kullanırlar.


11

Sergey'in ev benzetmesini seviyorum , ancak araba benzetmesinin daha iyi olacağını düşünüyorum.

Değişken tiplerini araba tipi, insanları veri olarak düşünün. Yeni bir araba ararken amacımıza en uygun olanı seçiyoruz. Sadece bir veya iki kişiye uyacak küçük bir akıllı araba istiyor muyuz? Yoksa daha fazla insan taşımak için bir limuzin? Her ikisinin de hız ve gaz kilometresi gibi avantajları ve dezavantajları vardır (hızı ve bellek kullanımını düşünün).

Bir limuzininiz varsa ve yalnız araba kullanıyorsanız, sadece size uyacak şekilde küçülmeyecektir. Bunu yapmak için, otomobili satmanız (okuyunuz: deallocate) ve kendiniz için yeni bir küçük araba almanız gerekir.

Analojiye devam ederek, hafızayı arabalarla dolu büyük bir park yeri olarak düşünebilirsiniz ve okumaya gittiğinizde, sadece arabanız için eğitilmiş özel bir şoför sizin için getirmeye gider. Aracınız içindeki insanlara bağlı olarak türleri değiştirebilirse, arabanızı almak istediğinizde her zaman bir sürü şoför getirmeniz gerekir, çünkü ne tür bir arabanın yerinde oturacağını asla bilemezler.

Başka bir deyişle, çalışma zamanında ne kadar bellek okumanız gerektiğini belirlemeye çalışmak çok verimsiz olabilir ve park yerinize birkaç araba daha sığabileceğinizden daha ağır basacaktır.


10

Bir kaç neden var. Birincisi, rasgele boyutlu sayıları işlemek için eklenen karmaşıklıktır ve bu, performansın her bir int'in tam olarak X bayt uzunluğunda olduğu varsayımına dayanarak optimizasyon yapamaması nedeniyle verir.

İkincisi, basit tiplerin bu şekilde depolanmasının, uzunluğu tutmak için ek bir bayta ihtiyaç duydukları anlamına gelir. Yani, 255 veya daha düşük bir değer aslında bu yeni sistemde bir değil iki bayta ihtiyaç duyuyor ve en kötü durumda şimdi 4 yerine 5 bayta ihtiyaç duyuyorsunuz. Bu, kullanılan bellek açısından performans kazanmanın yapabileceğinizden daha az olduğu anlamına geliyor. düşünün ve bazı durumlarda aslında net bir kayıp olabilir.

Üçüncü neden, bilgisayar belleğinin genellikle kelimelerle adreslenebilmesidir baytlara değil . (Ama dipnota bakınız). Sözcükler, genellikle 32 bit sistemlerde 4 ve 64 bit sistemlerde 8 baytın katlarıdır. Genellikle tek bir bayt okuyamazsınız, bir kelime okursunuz ve n. Baytı o kelimeden çıkarırsınız. Bu, bir sözcükten ayrı ayrı baytlar çıkarmanın yalnızca tüm sözcüğü okumaktan biraz daha fazla çaba gerektirdiği ve tüm belleğin kelime boyutlu (yani 4 bayt boyutlu) parçalara eşit olarak bölünmesinin çok etkili olduğu anlamına gelir. Çünkü, etrafta rastgele boyutlandırılmış tamsayılarınız varsa, tamsayıların bir kısmının bir kelimede, diğerinin sonraki kelimesinde tam tamsayıyı elde etmek için iki okuma yapılması gerekebilir.

Dipnot: Daha kesin olmak gerekirse, baytlarla uğraşırken, çoğu sistem 'düzensiz' baytları yoksaymıştır. Yani adres 0, 1, 2 ve 3 aynı kelimeyi okur, 4, 5, 6 ve 7 sonraki kelimeyi okur, vb.

Silinmemiş bir notta, 32 bit sistemlerin maksimum 4 GB belleğe sahip olmasının nedeni de budur. Bellekteki konumları ele almak için kullanılan kayıtlar genellikle bir kelimeyi tutacak kadar büyüktür, yani (2 ^ 32) -1 = 4294967295 maksimum değerine sahip 4 bayt, 4 GB'dir.


8

C ++ standart kütüphanesinde bir anlamda değişken boyuta sahip nesneler vardır std::vector. Ancak, bunların hepsi dinamik olarak ihtiyaç duyacakları ekstra belleği ayırır. Eğer alırsanız sizeof(std::vector<int>), nesne tarafından yönetilen bellekle hiçbir ilgisi olmayan bir sabit elde edersiniz ve içeren bir dizi veya yapı tahsis ederseniz std::vector<int>, ekstra depolama alanını aynı diziye veya yapıya koymak yerine bu temel boyutu ayıracaktır. . Bunun gibi bir şeyi, özellikle değişken uzunluklu dizileri ve yapıları destekleyen birkaç C sözdizimi vardır, ancak C ++ bunları desteklemeyi seçmedi.

Dil standardı, nesne boyutunu bu şekilde tanımlar, böylece derleyiciler verimli kod üretebilir. Örneğin, eğer intbazı uygulanmasına ilişkin 4 bayt uzunluğunda olur ve beyan abir işaretçi veya dizisi olarak intdaha sonra, değerler a[i], pseudocode çevirir “Adres a + 4 × i KQUEUE.” Bu sabit bir zamanda yapılabilir ve o kadar yaygın ve önemli bir işlemdir ki x86 ve üzerinde C'nin geliştirildiği DEC PDP makineleri de dahil olmak üzere birçok komut setli mimarinin bunu tek bir makine talimatında yapabilmesi mümkündür.

Değişken uzunluklu birimler olarak ardışık olarak depolanan verilerin ortak gerçek dünyadaki bir örneği UTF-8 olarak kodlanan dizelerdir. (Ancak, derleyiciye bir UTF-8 dizesinin yatan tip hala edilir char1. genişliği Bu ASCII dizeleri geçerli UTF-8 ve kütüphane kod gibi bir çok şekilde yorumlanmalıdır sağlar ve gelmiştir strlen()ve strncpy()işe devam etmek.) Herhangi bir UTF-8 kod noktasının kodlaması bir ila dört bayt uzunluğunda olabilir ve bu nedenle, bir dizede beşinci UTF-8 kod noktasını istiyorsanız, beşinci bayttan on yedinci bayta kadar herhangi bir yerden başlayabilir. Onu bulmanın tek yolu, dizenin başından itibaren taramak ve her kod noktasının boyutunu kontrol etmektir. Beşinciyi bulmak istiyorsan grafiği, karakter sınıflarını da kontrol etmeniz gerekir. Bir dizede milyonuncu UTF-8 karakterini bulmak istiyorsanız, bu döngüyü milyon kez çalıştırmanız gerekir! Endekslerle sık sık çalışmanız gerektiğini biliyorsanız, dizeyi bir kez geçip dizini oluşturabilirsiniz - veya UCS-4 gibi sabit genişlikte bir kodlamaya dönüştürebilirsiniz. Bir dizede milyonuncu UCS-4 karakterini bulmak, dizinin adresine dört milyon eklemektir.

Değişken uzunluktaki verilerle ilgili bir başka sorun da, ayırdığınızda, ya olabildiğince fazla bellek ayırmanız veya gerektiğinde dinamik olarak yeniden tahsis etmeniz gerektiğidir. En kötü durum için tahsis etmek son derece savurgan olabilir. Ardışık bir bellek bloğuna ihtiyacınız varsa, yeniden tahsis, tüm verileri farklı bir konuma kopyalamaya zorlayabilir, ancak belleğin ardışık olmayan yığınlarda saklanmasına izin vermek program mantığını zorlaştırır.

Yani, değişken uzunlukta bignums yerine sabit genişliğe sahip olmak mümkündür short int, int, long intve long long int, ancak tahsis ve bunları kullanmak için verimsiz olur. Ek olarak, tüm ana CPU'lar sabit genişlikli kayıtlarda aritmetik yapmak üzere tasarlanmıştır ve hiçbirinin doğrudan bir çeşit değişken uzunlukta bignum üzerinde çalışan talimatları yoktur. Bunların yazılımda çok daha yavaş uygulanması gerekir.

Gerçek dünyada, çoğu (ancak hepsi değil) programcı UTF-8 kodlamasının, özellikle uyumluluğun avantajlarının önemli olduğuna ve önden arkaya bir dize taramaktan veya Değişken genişliklerin dezavantajlarının kabul edilebilir olduğu bellek. Diğer şeyler için UTF-8'e benzer paketlenmiş, değişken genişlikli öğeler kullanabiliriz. Ama çok nadiren yapıyoruz ve standart kütüphanede değiller.


7

Değeri temsil etmek için gereken alan bu boyuttan daha küçük olabiliyorsa, neden bir türün kendisiyle ilişkilendirilmiş yalnızca bir boyutu vardır?

Öncelikle hizalama gereklilikleri nedeniyle.

Basic.align / 1 uyarınca :

Nesne türlerinin, bu tür bir nesnenin tahsis edilebileceği adreslere kısıtlamalar getiren hizalama gereksinimleri vardır.

Çok katlı ve her katta çok sayıda oda bulunan bir bina düşünün.
Her oda, N kişi veya nesneyi tutabilen boyutunuz (sabit bir alan).
Önceden bilinen oda büyüklüğü ile binanın yapısal bileşenini iyi yapılandırır .

Odalar hizalanmamışsa, bina iskeleti iyi yapılandırılmayacaktır.


7

Daha az olabilir. İşlevi düşünün:

int foo()
{
    int bar = 1;
    int baz = 42;
    return bar+baz;
}

montaj kodunu derler (g ++, x64, ayrıntılar çıkarılmış)

$43, %eax
ret

Burada barve baztemsil etmek için sıfır bayt kullanarak sona.


5

Neden myInt sadece 1 bayt bellek işgal etmiyor?

Çünkü ona bu kadarını kullanmasını söyledin. A kullanılırken unsigned int, bazı standartlar 4 bayt kullanılacağını ve bunun için kullanılabilir aralığın 0 ila 4.294.967.295 olacağını belirtir. unsigned charBunun yerine bir tane kullanacak olsaydınız, muhtemelen yalnızca aradığınız 1 baytı kullanırsınız (standarda bağlı olarak ve C ++ normalde bu standartları kullanır).

Bu standartlar olmasaydı bunu aklınızda bulundurmanız gerekir: derleyici veya CPU'nun 4 yerine 1 bayt kullanmayı nasıl bilmesi gerekir? Daha sonra programınızda daha fazla alan gerektiren bu değeri ekleyebilir veya çarpabilirsiniz. Bir bellek ayırma işlemi yaptığınızda, işletim sistemi size bu alanı bulmalı, eşlemeli ve vermelidir (muhtemelen belleği sanal RAM'e de değiştirebilir); bu uzun zaman alabilir. Belleği önceden ayırırsanız, başka bir ayırmanın tamamlanmasını beklemek zorunda kalmazsınız.

Bayt başına 8 bit kullanmamızın nedenine gelince, şuna bakabilirsiniz: Baytın neden sekiz bit olduğunun tarihi nedir?

Yan notta, tamsayının taşmasına izin verebilirsiniz; ancak işaretli bir tamsayı kullanırsanız, C \ C ++ standartları, tamsayı taşmalarının tanımsız davranışa neden olduğunu belirtir. Tamsayı taşması


5

Çoğu cevabın kaçırdığı basit bir şey:

çünkü C ++ 'ın tasarım hedeflerine uygundur.

Bir türün derleme zamanında çalışabilmesi, derleyici ve programcı tarafından çok sayıda basitleştirici varsayım yapılmasına olanak tanır, bu da özellikle performans açısından birçok fayda sağlar. Tabii ki, sabit boyutlu tipler, tamsayı taşması gibi eşlik eden tuzaklara sahiptir. Bu nedenle farklı diller farklı tasarım kararları alır. (Örneğin, Python tamsayıları esasen değişken boyuttadır.)

Muhtemelen C ++ 'nın sabit boyutlu tiplere bu kadar güçlü bir şekilde eğilmesinin ana nedeni, C uyumluluğu hedefidir. Bununla birlikte, C ++, çok verimli bir kod üretmeye çalışan ve programcı tarafından açıkça belirtilmeyen şeyleri eklemekten kaçınan statik olarak yazılan bir dil olduğundan, sabit boyutlu türler hala çok mantıklıdır.

Peki neden C sabit ebatlı tipleri tercih etti? Basit. 70'lerin işletim sistemlerini, sunucu yazılımlarını ve yardımcı programları yazmak için tasarlanmıştır; diğer yazılımlar için altyapı (bellek yönetimi gibi) sağlayan şeyler. Bu kadar düşük bir seviyede, performans kritiktir ve derleyici de tam olarak söylediklerinizi tam olarak yapar.


5

Bir değişkenin boyutunu değiştirmek için yeniden konumlandırma gerekir ve bu genellikle birkaç bayt bellek harcamasına kıyasla ek CPU döngülerine değmez.

Yerel değişkenler, bu değişkenlerin boyutu değişmediğinde işlemesi çok hızlı olan bir yığına gider. Bir değişkenin boyutunu 1 bayttan 2 bayta genişletmek istediğinize karar verdiyseniz, bu alanı açmak için yığındaki her şeyi bir bayt taşımalısınız. Bu, kaç şeyin taşınması gerektiğine bağlı olarak çok fazla CPU döngüsüne mal olabilir.

Bunu yapabilmenin başka bir yolu, her değişkeni bir yığın konumuna işaretçi yapmaktır, ancak aslında daha fazla CPU döngüsü ve bellek harcarsınız. İşaretçiler 4 bayt (32 bit adresleme) veya 8 bayttır (64 bit adresleme), bu nedenle işaretçi için zaten 4 veya 8, ardından yığıntaki verilerin gerçek boyutunu kullanıyorsunuz. Bu durumda yeniden tahsis için hala bir maliyet vardır. Öbek verilerini yeniden tahsis etmeniz gerekiyorsa, şanslı olabilir ve satır içi genişletmek için yer olabilir, ancak bazen istediğiniz boyutta bitişik bellek bloğuna sahip olmak için yığın üzerinde başka bir yere taşımanız gerekir.

Önceden ne kadar bellek kullanılacağına karar vermek her zaman daha hızlıdır. Dinamik boyutlandırmadan kaçınabiliyorsanız performans elde edersiniz. Bellek kaybı genellikle performans kazancına değer. Bu yüzden bilgisayarların tonlarca belleği var. :)


3

Derleyici, işler devam ettiği sürece ("olduğu gibi" kuralı) kodunuzda birçok değişiklik yapmasına izin verilir.

Bir tam taşımak için gereken daha uzun (32/64 bit) yerine 8 bitlik bir gerçek hareket talimatı kullanmak mümkün olacaktır int. Ancak, yükü tamamlamak için iki yönerge gerekir, çünkü yükü yapmadan önce kaydı sıfıra ayarlamanız gerekir.

Değeri 32 bit olarak işlemek daha basittir (en azından ana derleyicilere göre). Aslında, satır içi montaj olmadan 8 bit yük yapacak bir x86 / x86_64 derleyicisi görmedim.

Ancak, 64 bit söz konusu olduğunda işler farklıdır. İşlemcilerinin önceki uzantılarını (16 ila 32 bit) tasarlarken Intel bir hata yaptı. İşte neye benzediklerinin iyi bir temsili. Burada ana paket AL ya da AH yazdığınızda, diğeri etkilenmez (yeterince adil, bu nokta ve o zaman mantıklı). Ancak 32 bite genişlettiklerinde ilginçleşiyor. Eğer alt bitleri (AL, AH veya AX) yazarsanız, hiçbir şey bir tanıtmak istiyorsanız demekse EAX üst 16 bit, olur charbir içine int, öncelikle bu hafızayı temizlemek için gerekir, ancak hiçbir şekilde bir var aslında sadece bu ilk 16 biti kullanarak bu "özelliği" her şeyden daha fazla acı haline getirir.

Şimdi 64 bit ile AMD çok daha iyi bir iş çıkardı. Alt 32 bitteki herhangi bir şeye dokunursanız, üst 32 bit basitçe 0'a ayarlanır. Bu, bu godbolt'ta görebileceğiniz bazı gerçek optimizasyonlara yol açar . 8 bit veya 32 bitlik bir şey yüklemenin aynı şekilde yapıldığını görebilirsiniz, ancak 64 bit değişkenleri kullandığınızda, derleyici hazır bilginizin gerçek boyutuna bağlı olarak farklı bir komut kullanır.

Burada gördüğünüz gibi, derleyiciler aynı sonucu üretecekse CPU'nuzdaki değişkeninizin gerçek boyutunu tamamen değiştirebilir, ancak daha küçük tipler için bunu yapmak mantıklı değildir.


düzeltme: as-if . Ayrıca, daha kısa bir yük / depo kullanılabiliyorsa, diğer baytları kullanım için nasıl serbest bırakacağını görmüyorum - bu OP'nin merak ettiği şey gibi görünüyor: sadece mevcut değer için gerekli olmayan belleğe dokunmaktan kaçınmak değil, ancak kaç bayt okunacağını söyleyebilir ve çalışma sırasında tüm RAM'leri sihirli bir şekilde değiştirebilir, böylece garip felsefi bir uzay verimliliği fikri (devasa performans maliyetine aldırmayın!) karşılanır ... bunu 'çözemez'. Bir CPU / OS'nin yapması gereken şey, soruyu en açık şekilde IMO'ya cevap verecek kadar karmaşık olacaktır.
underscore_d

1
Ancak kayıtlarda gerçekten "bellek tasarrufu" olamaz. AH ve AL'yi kötüye kullanarak garip bir şey yapmaya çalışmadığınız sürece, yine de aynı genel amaçlı kayıtta birkaç farklı değere sahip olamazsınız. Yerel değişkenler genellikle kayıtlarda kalır ve gerekmediğinde RAM'e asla gitmez.
meneldal
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.