Intel işlemciler (ve belki bazıları da) depolama için küçük endian biçimini kullanır.
Her zaman birisinin neden baytları ters sırayla saklamak istediğini merak ediyorum. Bu formatın büyük endian formatına göre herhangi bir avantajı var mı?
Intel işlemciler (ve belki bazıları da) depolama için küçük endian biçimini kullanır.
Her zaman birisinin neden baytları ters sırayla saklamak istediğini merak ediyorum. Bu formatın büyük endian formatına göre herhangi bir avantajı var mı?
Yanıtlar:
Her iki şekilde de argümanlar var, ancak bir nokta, küçük endian sisteminde, 32, 16 veya 8 bit genişliğinde alınan bellekteki belirli bir değerin adresinin aynı olmasıdır.
Başka bir deyişle, bellekte iki baytlık bir değer varsa:
0x00f0 16
0x00f1 0
'16' değerini 16 bitlik bir değer olarak (çoğu 32 bit sistemde c 'kısa') veya 8 bitlik bir değer olarak (genellikle c 'char') almak yalnızca kullandığınız getirme talimatını değiştirir - aldığınız adresi değil dan.
Büyük bir endian sisteminde, yukarıdaki gibi düzenlenmiştir:
0x00f0 0
0x00f1 16
işaretçiyi artırmanız ve ardından yeni değerde daha dar alma işlemi gerçekleştirmeniz gerekir.
Yani, kısacası, 'küçük endian sistemlerinde, yayınlar işlemez.'
Her zaman birisinin neden baytları ters sırayla saklamak istediğini merak ediyorum.
Büyük-endian ve küçük-endian, insan bakış açısına göre sadece "normal sıra" ve "ters sıra" dır ve daha sonra bunların hepsi doğruysa ...
Bunların hepsi bir CPU için hiç önemi olmayan insan sözleşmeleridir. # 1 ve # 2'yi elinde tutup 3'ü çevirirseniz, küçük endian, Arapça veya İbranice okuyan ve sağdan sola yazılan insanlara "tamamen doğal" görünür.
Ve doğal olmayan görünen büyük-endian yapan başka insan sözleşmeleri var.
Çoğunlukla 68K ve PowerPC'yi programlarken büyük-endian'ın "doğru" ve küçük-endian'ın "yanlış" olduğunu düşündüm. Fakat daha fazla ARM ve Intel çalışması yaptığım için, küçük endianlara alışmıştım. Gerçekten önemli değil.
Tamam, işte bana açıklamamın nedeni: Toplama ve çıkarma
Çok baytlı sayıları topladığınızda veya çıkardığınızda, en az anlamlı baytla başlamanız gerekir. Örneğin, iki adet 16 bitlik bir sayı ekliyorsanız, en az anlamlı bayttan en anlamlı bayta kadar bir taşıma olabilir, bu nedenle bir taşıma olup olmadığını görmek için en az anlamlı byte ile başlamanız gerekir. Bu, el yazısı eklemesi yaparken en sağdaki rakamla başlamanızın nedenidir. Soldan başlayamazsın.
Bellekten sırayla bayt alan 8 bit bir sistem düşünün. O en düşük değerli baytı getirir Eğer ilk , bu ek yaparak başlayabilirsiniz ise en önemli byte bellekten alınıyor. Bu paralellik, performansın sistem gibi küçük çetelerde daha iyi olmasının nedenidir. Her iki bayt da bellekten alınana kadar beklemek ya da bunları ters sırada almak zorunda kalırsa daha uzun sürer.
Bu eski 8-bit sistemlerde. Modern bir CPU'da bayt sırasının herhangi bir fark yarattığından şüpheliyim ve sadece tarihsel nedenlerden dolayı küçük endian kullanıyoruz.
8 bit işlemcileri ile kesinlikle daha verimli oldu, farklı bir koda gerek duymadan ve ekstra değerleri tamponlamaya gerek kalmadan 8 veya 16 bitlik bir işlem gerçekleştirebilirsiniz.
Her seferinde bir bayt satıyorsanız, bazı ek işlemler için hala daha iyidir.
Ancak büyük endian'ın daha doğal olması için hiçbir neden yoktur - İngilizce'de on üç (küçük endian) ve yirmi üç (büyük endian) kullanıyorsunuz
0x12345678
gibi depolanır (bayt 0 solda, bayt 3 sağdadır). Sayının ne kadar büyük olduğunu (bit cinsinden) ne kadar büyükse o kadar fazla gerektirir; Bir WORD bir takas gerektirir; bir DWORD, iki geçiş (toplam üç adet swap); bir QWORD üç geçişi (toplam 7), vb. Yani, takas. Başka bir seçenek ikisini de ileriye okuyor ve geriye (her bayt ileri okuma, ancak geriye bütün # tarayarak). 78 56 34 12
12 34 56 78
(bits/8)-1
Japon tarih konvansiyonu "büyük endian" - yyyy / mm / gg. Bu, normal ilk karakter olan en önemli kural olan basit bir dize karşılaştırmasını kullanabilen algoritmaları sıralamak için kullanışlıdır.
Benzer bir şey, en önemli alan-ilk kaydında saklanan büyük-endian numaraları için de geçerlidir. Alanlardaki baytların önem sırası, kayıt içindeki alanların önemi ile eşleşir; bu nedenle memcmp
, iki uzun kod, dört sözcük veya sekiz ayrı bayt karşılaştırmanıza bakılmaksızın bir kayda değer kullanabilirsiniz .
Alanların önem sırasını çevirin ve aynı avantajı elde edin, ancak büyük endian yerine küçük endian sayıları için.
Bunun elbette çok az pratik önemi var. Platformunuz büyük veya küçük endian olsa da, gerçekten ihtiyacınız varsa bu numaradan yararlanmanız için bir kayıt alanı sipariş edebilirsiniz. Taşınabilir kod yazmanız gerekirse, sadece bir acıdır .
Klasik itiraz için bir link de ekleyebilirim ...
http://tools.ietf.org/rfcmarkup?url=ftp://ftp.rfc-editor.org/in-notes/ien/ien137.txt
DÜZENLE
Ekstra bir düşünce. Bir keresinde büyük bir tamsayı kütüphanesi yazdım (görebiliyor muyum görmek için) ve bunun için, 32-bitlik geniş parçalar platformun bu parçalardaki bitleri nasıl sıraladığından bağımsız olarak küçük-endian düzende saklanır. Sebepler ...
Birçok algoritma doğal olarak en az kayda değer uçta çalışmaya başlar ve bu uçların eşleşmesini ister. Örneğin, ek olarak, taşıyıcılar giderek daha fazla önemli haneye yayılmaktadır, bu nedenle en az anlamlı uçtan başlamak mantıklıdır.
Bir değeri büyütmek veya küçültmek, yalnızca parçaların toplanması / kaldırılması anlamına gelir - parçaların yukarı / aşağı kaydırılması gerekmez. Belleğin yeniden konumlandırılması nedeniyle kopyalama işlemi hala gerekli olabilir, ancak sık sık değil.
Bunun elbette işlemcilerle ilgisi yok - elbette - CPU'lar donanım tamsayılı desteği ile yapılıncaya kadar, tamamen bir kütüphane meselesi.
Bunun yapılabileceği NEDEN başka hiç kimse cevap vermedi, sonuçları hakkında çok şey var.
Belirli bir saat döngüsünde bellekten tek bir bayt yükleyebilen 8 bit bir işlemci düşünün.
Şimdi, eğer 16 bitlik bir değere sahip olmak istiyorsanız, sahip olduğunuz tek ve tek 16 bitlik kasaya (örneğin, program sayacı), o zaman bunu yapmanın basit bir yolu:
sonuç: yalnızca alma konumunu artırırsınız, yalnızca daha geniş kayıt listenizin düşük dereceli bölümüne yüklersiniz ve yalnızca sola kaydırmanız gerekir. (Tabii ki, sağa kaydırmak diğer işlemler için yararlıdır, bu yüzden bu bir yan gösteri birazdır.)
Bunun bir sonucu olarak, 16 bitlik (çift baytlık) öğelerin Most sırayla saklanmasıdır. Yani, küçük adres en önemli bayta sahiptir - çok büyük endian.
Bunun yerine küçük endian kullanarak yüklemeyi denediyseniz, geniş yazıcınızın alt kısmına bir bayt yüklemeniz, ardından bir sonraki baytı bir hazırlama alanına yüklemeniz, kaydırmanız ve daha sonra geniş yazıcınızın üst kısmına yerleştirmeniz gerekir. . Veya seçici olarak üst veya alt byte'a yükleyebilmek için daha karmaşık bir düzenleme düzenini kullanın.
Küçük endian'a gitmeye çalışmanın sonucu ya daha fazla silikona (anahtarlar ve kapılar) ya da daha fazla operasyona ihtiyaç duymanızdır.
Başka bir deyişle, eski günlerde paranın karşılığını alma konusunda, çoğu performans ve en küçük silikon alanı için daha fazla patlama elde ettiniz.
Bu günlerde, bu düşünceler ve hemen hemen alakasız, ancak boru hattı dolgusu gibi şeyler hala büyük bir sorun olabilir .
S / w yazma söz konusu olduğunda, küçük endian adresleme kullanıldığında hayat sıklıkla daha kolaydır.
(Ve büyük endian işlemciler bit-in-bayt cinsinden bayt sıralaması ve küçük endian açısından büyük endian olma eğilimindedirler. Ancak bazı işlemciler garip ve bayt sıralaması yanı sıra sipariş büyük endian bit kullanacaktır. Bu hayat yapar çok Bellek eşlemeli çevre birimleri ekleyen salak tasarımcı için ilginç ancak programcının başka bir sonucu yok.)
jimwise iyi bir noktaya değindi. Başka bir sorun var, küçük endian'da şunları yapabilirsiniz:
byte data[4];
int num=0;
for(i=0;i<4;i++)
num += data[i]<<i*8;
OR
num = *(int*)&data; //is interpreted as
mov dword data, num ;or something similar it has been some time
Hafızadaki yer değiştirilen yerlerin bariz dezavantajından etkilenmeyen programcılar için daha yalındır. Şahsen ben doğal olanın tersi olan büyük endian buluyorum :). 12 21 gibi kaydedilmeli ve yazılmalıdır :)
for(i=0; i<4; i++) { num += data[i] << (24 - i * 8); }
karşılık geliyor move.l data, num
.
Her zaman birisinin neden baytları ters sırada depolamak istediğini merak ediyorum.
Ondalık sayı büyük endian ile yazılmıştır. Aynı zamanda İngilizce dilinde nasıl yazdığınız, en önemli rakamla, en önemlisi de en önemlisi olanı ile başlarsınız. Örneğin
1234
bin, iki yüz otuz dört.
Bu şekilde büyük endian bazen doğal düzen denir.
Küçük endian'da, bu sayı bir, yirmi, üç yüz dört bin olur.
Bununla birlikte, toplama veya çıkarma gibi aritmetik işlem yaptığınızda, bitişle başlarsınız.
1234
+ 0567
====
4 ve 7 ile başlarsınız, en düşük rakamı yazıp taşımayı hatırlayın. Sonra 3 ve 6 vb. Eklersiniz. Toplamak, çıkarmak veya karşılaştırmak için, eğer sayıları tersine çevirirseniz, hafızayı sırayla okumak için mantık varsa, uygulanması daha kolaydır.
Büyük endian'ı bu şekilde desteklemek için, belleği tersten okuyabilmek için mantığa ihtiyacınız var, ya da sadece kayıtlar üzerinde çalışan RISC işleminiz var. ;)
Intel x86 / Amd x64 tasarımının çoğu tarihidir.
Big-endian bazı işlemler için kullanışlıdır (eşit oktet uzunluktaki yayların "bignumlarının" karşılaştırılması). Diğerleri için Little-endian (muhtemelen iki "bignum" ekleyerek). Sonunda, CPU donanımının ne için kurulduğuna bağlı, genellikle bir veya diğeri (bazı MIPS yongaları IIRC, önyüklemede LE veya BE olacak şekilde değiştirilebilir).
Yalnızca değişken uzunluklarda depolama ve aktarma söz konusu olduğunda, ancak birden fazla değere sahip hiçbir aritmetik olmadığında, LE'nin yazması genellikle kolaydır, BE'nin okunması daha kolaydır.
Belirli bir örnek olarak bir dizgeden int'ye dönüşüm (ve geri) alalım.
int val_int = 841;
char val_str[] = "841";
İnt dizgeye dönüştürüldüğünde, en az anlamlı olan rakam, en önemli olan rakamdan daha kolaydır. Hepsi basit bir son koşul ile basit bir döngüde yapılabilir.
val_int = 841;
// Make sure that val_str is large enough.
i = 0;
do // Write at least one digit to care for val_int == 0
{
// Constants, can be optimized by compiler.
val_str[i] = '0' + val_int % 10;
val_int /= 10;
i++;
}
while (val_int != 0);
val_str[i] = '\0';
// val_str is now in LE "148"
// i is the length of the result without termination, can be used to reverse it
Şimdi aynısını BE sırayla deneyin. Genellikle, belirli bir sayı için 10'un en büyük gücüne sahip başka bir bölene ihtiyacınız vardır (burada 100). İlk önce bunu bulman gerek, elbette. Yapacak daha çok şey var.
İnt dönüştürme dizesi, ters yazma işlemi olarak yapıldığında, BE'de yapmak daha kolaydır. Yazma en son haneyi depolar, bu yüzden ilk önce okunması gerekir.
val_int = 0;
length = strlen(val_str);
for (i = 0; i < length; i++)
{
// Again a simple constant that can be optimized.
val_int = 10*val_int + (val_str[i] - '0');
}
Şimdi aynısını LE sırasına göre yapın. Yine, 1 ile başlayan ve her hane için 10 ile çarpılan ek bir faktöre ihtiyacınız olacaktır.
Bu yüzden genellikle BE'yi depolamak için kullanmayı tercih ederim, çünkü bir değer tam olarak bir kez yazılır, ancak en az bir kez ve belki de birçok kez okunur. Daha basit yapısı için, genellikle LE'ye dönüştürme yolunu izlerim ve sonra değeri ikinci kez yazsa bile sonucu tersine çeviririm.
BE depolama için başka bir örnek UTF-8 kodlaması ve daha pek çoğu olabilir.