Küçük Endian Sayıdan Dizeye Dönüşüm


13

Giriş

BMP (bitmap) jeneratörü ile çalışma sırasında sayıyı küçük endian hex dizesine dönüştürme problemiyle karşı karşıyayım. İşte JavaScript'te oluşturduğum işlev - ama küçük kodun nasıl çalışabileceğini merak ediyorum

let liEnd= num => num.toString(16).padStart(8,'0').match(/../g).reverse().join``;
console.log(liEnd(304767)) // 304767 dec = 0x4a67f hex

Meydan okuma

Girişte 32 bit işaretsiz tam sayı alacak ve az endian düzeniyle 8 basamaklı onaltılık dize üretecek yazma işlevi. İşi yapan örnek algoritma:

  • uyuşmayı onaltılık dizeye dönüştürmek ör: 304767 -> '4a67f'
  • 8 karakterlik dize almak için dolgu sıfırları ekleyin: '0004a67f'
  • dizeyi dört adet 2 karakterlik parçaya bölme: '00','04','a6','7f'
  • parçaların ters sırası '7f','a6','04','00'
  • parçaları birleştirmek ve sonuç olarak iade: '7fa60400'

Örnek Giriş ve Çıkış

Girdi numarası (veya dec numaralı dize) solunda ->, çıktı hex dizesi sağda

2141586432 -> 0004a67f
304767     -> 7fa60400

Yanıtlar:


7

05AB1E , 10 9 bayt

žJ+h¦2ôRJ

Çevrimiçi deneyin!

Jelly cevabından ilham alarak -1 byte.

žJ+   add 2^32 to input
h     convert to hex
¦     drop leading 1
2ô    split in groups of 2
R     reverse groups
J     and join them

6

Python 3 , 37 bayt

lambda n:n.to_bytes(4,"little").hex()

Çevrimiçi deneyin!

Aritmetik tabanlı özyinelemeli çözüm ( 50 49 bayt, Python 2 için de çalışır ) :

f=lambda n,i=4:i*'1'and"%02x"%(n%256)+f(n>>8,i-1)

Çevrimiçi deneyin!

@JonathanAllan sayesinde -1 bayt


Özyinelemeli olanı bir Python 2 girişi olarak gönderin :)
Jonathan Allan

f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)bir bayt kaydeder :)
Jonathan Allan

@JonathanAllan Teşekkürler. Tüm Python 2 hilelerine aşina değilim ve nasıl daha kısa hale getirilebileceğini görmüyorum.
Joel

37 değil, py 2'de çalışmaz
Jonathan Allan

Evet. Bu yerleşiklerin bazıları sadece Python-3'tür.
Joel

6

R , 54 53 bayt

format.hexmode(scan()%/%256^(0:3)%%256%*%256^(3:0),8)

Çevrimiçi deneyin!

2 karakterlik her bir grup aslında taban 256'daki bir basamağın onaltılık temsilidir. scan()%/%256^(0:3)%%2564 basamaklı ters ...%*%256^(3:0)bir sayıya format.hexmode(...,8)dönüştürür , bunları tek bir tamsayı olarak birleştirir ve bu sayıyı 8 basamaklı onaltılı temsiline dönüştürür.


5

JavaScript (ES7),  59  57 bayt

Dize düzenleme.

n=>(n+2**32).toString(16).match(/\B../g).reverse().join``

Çevrimiçi deneyin!

Nasıl?

n+2320

(304767 + 2**32).toString(16) // --> '10004a67f'

Çevrimiçi deneyin!

/\B../g1\B

'10004a67f'.match(/\B../g) // --> [ '00', '04', 'a6', '7f' ]

Çevrimiçi deneyin!

Biz reverse()ve join()son ipi almak için.


JavaScript (ES6), 61 bayt

Özyinelemeli işlev.

f=(n,k=4)=>k?[(x=n&255)>>4&&'']+x.toString(16)+f(n>>8,k-1):''

Çevrimiçi deneyin!


⭐ - güzel cevap için yıldız olsun - Seviyorum, kısa ama yine de temiz ve "insan tarafından redable" :)
Kamil Kiełczewski


5

C # (Visual C # Etkileşimli Derleyici) , 54 bayt

x=>$"{(x=x>>16|x<<16)>>8&16711935|(x&16711935)<<8:x8}"

@PeterCordes sayesinde 4 bayt tasarruf edildi

Çevrimiçi deneyin!

açıklama

x=>                                                    //Lambda taking in an uint
     (x=x>>16|x<<16)                                   //Swap the first two and the last two bytes of the uint (0x7fa60400 -> 0x04007fa6)
                    >>8&16711935|(x&16711935)<<8       //Swap each pair of bytes in every group of 2 bytes (0x04007fa6 -> 0x0004a67f)
  $"{                                           :x8}"  //Format as hex string, padded with leading zeroes to length 8

Maskelemeden önce kaydırırsanız 4278255360maskeyi sabit olarak 16711935( 0xff00ff) küçültebilir misiniz ? Yoksa ekstra parensiye mi mal oluyor? Ayrıca, o zaman değilse , aynı uzunluk ama insanlar için çok daha anlamlı. 0xff00ff00
Peter Cordes

@PeterCordes Ayrıca toplamda 4 bayt tasarruf sağlayan parantezleri >>daha yüksek önceliğe sahip olarak kaldırabilme avantajına sahiptir &. Teşekkürler!
Cehalet

Güzel. "Açıklama" bölümünde sabitleri onaltılı olarak yazmanızı öneririm.
Peter Cordes

4

Japt -P , 10 bayt

sG ùT8 ò w

Dene

sG ùT8 ò w     :Implicit input of integer
s              :Convert to string
 G             :  In base-16
   ù           :Left pad
    T          :  With 0
     8         :  To length 8
       ò       :Split into 2s
         w     :Reverse
               :Implicitly join and output

Ne yapar -P?
SS Anne

🚀 cevabınız üstte (açıklama ekleyebilir misiniz?)
Kamil Kiełczewski

@ JL2210 Dokümanlardan : " -P: Çıktı bir dizi ise, ayırıcıP içermeyen çıktılar (örn . İle birleştirilir ). " Bayrak bayt kaydetmek için açık birleştirme yerine örtük içindir. :)
Kevin Cruijssen

2
@ KamilKiełczewski, açıklama eklendi.
Shaggy


4

Python 2 , 43 bayt

lambda n:[("%08x"%n)[i^6]for i in range(8)]

Çevrimiçi deneyin!

Benrg sayesinde -4 bayt

Bir karakter listesi çıkarır. Endekslerdeki girdinin onaltılık basamağını sırayla alarak hesaplanır 6, 7, 4, 5, 2, 3, 0, 1.


2
[i^6]for i in range(8)birkaç bayt kaydeder.
benrg

Dize yerine liste çıktısına izin veriliyor mu?
Qwertiy

liste olarak çıktı gerçekten imo ruhu için uygun değil
qwr

3

C (gcc) endian agnostik, standart libs yok, 92 91 bayt

h(n)tek basamaklı tam sayı-> altıgen yardımcı fonksiyonudur.
f(x,p)bir tamsayı ve bir char[8]işaretçi alır. Sonuç 8 baytlık charveri. ( Not arayan bu yapmazsa 0-sonlu).

Varsayımlar: ASCII karakter kümesi. 2'ye tümleyen intdoğru kayması böylece sonunda işareti biraz aşağı getirir ve bir dönüştürme uint32_tiçin intyüksek bit kümesi ise bit deseni gizleyin etmez. inten az 32 bittir. (Daha geniş, 1'in tamamlayıcısı veya işaret büyüklüğü C uygulamaları üzerinde çalışmasına izin verebilir).

Varsayımlar: uygulama bayt sırası veya imzası hakkında herhangi bir şey char.

i;h(n){n&=15;return n>9?n+87:n+48;}f(x,p)char*p;{for(i=5;--i;x>>=8)*p++=h(x>>4),*p++=h(x);}

Çevrimiçi deneyin! printf("%.8s\n", buf)0 sonlandırmadan çıktı arabelleğini yazdırmak için kullanılan test arayanı dahil .

Ungolfed:

int h(n){n&=15;return n>9 ? n+'a'-10 : n+'0';}      // single digit integer -> hex

int i;
void ungolfed_f(x,p)char*p;{
    for(i=5; --i; x>>=8)   // LS byte first across bytes
        *p++=h(x>>4),      // MS nibble first within bytes
        *p++=h(x);
}

Yapma n&=15;içini h(x)başabaş olduğu; Her &15iki çağrı sitesinde düşük kemirmek izole etmek için her biri 6 bayt ve 3 bayt.

,bir dizi noktasıdır (veya modern terminolojide eşdeğerdir), bu nedenle operatör *p++= stufftarafından ayrıldığında bir ifadede iki kez yapmak güvenlidir ,.

>>imzalı tamsayıda uygulama aritmetik veya mantıksal olarak tanımlanır. GNU C bunu aritmetik 2'nin tamamlayıcısı olarak tanımlar. Ancak herhangi bir 2'nin tamamlayıcı makinesinde bu gerçekten önemli değil çünkü kaymış 0'lara veya işaret bitinin kopyalarına asla bakmıyoruz. Orijinal MSB sonunda düşük bayta değişecektir. Bu işaret / büyüklükte durum değildir ve 1'in tamamlayıcısından emin değilim.

Yani bu sadece 2'nin tamamlayıcı C uygulamalarına taşınabilir. (Ki burada ya intbir geniş . 32'den bit çok 31 büyüklük sadece bir parçası bit) imzasız -> imzalı dönüşümü de munges çok negatif tamsayı bit-desen, &15bir on intsadece 2'nin tamamlayıcı orijinal işaretsiz değer nibbles elde olacaktır. Yine, 32- bit'den daha geniş olmadığı sürece int, tüm girişler negatif değildir.

Golf edilmiş versiyon, UB'nin geçersiz bir fonksiyonun sonundan düşmesini sağlar. Bir değer döndürmemek, sadece voidvarsayılan yerine bildirmekten kaçınmak için int. Modern derleyiciler bunu optimizasyon etkinken kıracak.


Motivasyon: Bir x86 veya ARM Thumb asm cevabı düşünüyordum, C'de manuel olarak yapmanın eğlenceli olabileceğini düşündüm, belki de başlangıç ​​noktası olarak derleyici tarafından oluşturulan asm için. Sadece 2 talimat içeren bir AVX512VBMI sürümü de dahil olmak üzere hızlı verimli x86 asm için /programming/53823756/how-to-convert-a-number-to-hex adresine bakın (ancak vpmultishiftqb ve vpshufb için kontrol vektörlerine ihtiyaç duyar) yani golf için harika olmaz). Normalde SIMD'nin küçük endian x86'da baskı sırasına göre bayt-tersine dönmesi için ekstra iş gerekir, böylece bu bayt-ters onaltılık çıkış aslında normalden daha kolaydır.


Diğer fikirler

Tamsayı referans alarak almayı ve char*küçük bir endian C uygulamasında (x86 veya ARM gibi) baytları üzerinde döngü yapmayı düşündüm . Ama bunun çok fazla tasarruf edeceğini sanmıyorum.

sprintfBir seferde 1 bayt, golf oynadıktan sonra 64 bayt yapmak için kullanma :

int i;
void f(x,p)char*p;{
        for(i=4;sprintf(p,"%.2x",x&255),--i;x>>=8)
                p+=2;
}

Ancak printf benzeri işlevler kullanırsak, byte-swap yapabilir ve @ JL2210'un yanıtı%x gibi her şeyin bir printf'ini yapabiliriz .


⭐ - güzel cevap için yıldız
alıyorsunuz

3

x86 SIMD makine kodu (AVX512-VBMI), 36 bayt

(16 bayt altıgen bir arama tablosu)

Bu, bir tamsayı alan xmm0ve xmm0arayanın istediği yerde saklaması için 8 bayt ASCII karakter verisi döndüren bir işlevdir . (örn. öznitelik baytlarıyla araya eklendikten sonra veya yapım aşamasında olan bir dizeye veya başka bir şeye) video belleğine)

C'den, __m128i retval = lehex(_mm_cvtsi32_si128(x))x86-64 System V çağrı kuralında veya MS Windows'da olduğu gibi çağırın vectorcall.

# disassembly with machine-code bytes (the answer) and NASM source code.
0000000000401000 <lehex>:
  401000:       c5 f1 72 d0 04          vpsrld      xmm1, xmm0, 4         ; AVX1
  401005:       c5 f1 60 c8             vpunpcklbw  xmm1, xmm1, xmm0      ; AVX1
  401009:    62 f2 75 08 8d 05 01 00 00 00 vpermb  xmm0, xmm1, [rel .hex_lut]
  401013:       c3                      ret    

0000000000401014 <lehex.hex_lut>:
  401014:     30 31 ...  61 62 ...     .hex_lut:  db "0123456789abcdef"

Toplam = 0x24 = 36 bayt.

Bkz. Bir sayıyı onaltılık biçime dönüştürme? bunun nasıl çalıştığı hakkında SO. (Vardiya / punpck için SSE2, daha sonra vpermbihtiyacımız olan işi kaydeder pshufb. SSE2 / SSSE3 yerine AVX1 de bir movapskayıt kopyasını önler .)

Bildirim o punpcklbwen düşük kaynak bayt en anlamsız kemirme sonra bize en düşük bayt elemanda düşük giriş byte en anlamlı yarım bayt verecek bu sırayla kaynak işlenen ile. (Bu SO cevabında, bswapgirişte sadece SSE2 ile standart baskı düzeninde bir sonuç elde etmek için kullanılır. Ancak burada bu siparişi istiyoruz : her bayt içindeki alt elemanda yüksek kırıntı, ama yine de küçük endian bayt sırası).

Daha fazla veri sabitimiz varsa, adres modlarını mov edx, imm32kullanarak [rdx+16]veya sonra herhangi bir adresleme modunu kullanarak adresleme modu alanından tasarruf edebiliriz . Veya vpbroadcastb xmm0, [rdx+1].

Ama bence 16 baytlık altıgen LUT + vpermbdurumu uygulamaktan daha iyi n>9 : n+'a'-10 : n+'0': AVX512BW bayt maskeleme (maske, karşılaştırma vpaddbbirleştirme maskeli vpaddb) veya daha fazla AVX1 veya SSE2 ile 3 sabit ve en az 3 talimat gerektirir . (Bunun SSE2 sürümü için SO'da bir sayıyı onaltılık biçime nasıl dönüştürürsünüz? ). Ve her AVX512BW komutu en az 6 bayt uzunluğundadır (4 bayt EVEX + opcode + modrm), adresleme modunda bir yer değiştirme ile daha uzundur.

Aslında en az 4 yönerge alacaktı çünkü karşılaştırmadan önce yüksek çöpleri andps(veya vpandd4 baytlık yayın hafızalı işlenen EVEX) temizlememiz gerekiyor . Ve bunların her birinin farklı bir vektör sabitine ihtiyacı var. AVX512, yalnızca 32 bit ve daha geniş öğeler için yayın bellek işlenenlerine sahiptir. Örneğin, EVEX'invpaddb son işleneni yalnızca xmm3/m128değil xmm3/m128/m8bcst. (Intel'in yük bağlantı noktaları, bir yük bölmesinin parçası olarak yalnızca 32 ve 64 bit yayınları ücretsiz olarak yapabilir, böylece Intel, AVX512BW'yi bunu yansıtacak şekilde tasarladı ve onlara bayt veya kelime yayını bellek işlenenlerini kodlayamayacak şekilde tasarlayamadı. sabitlerinizi 4 bayta sıkıştırabilmeniz için dword yayınları yapın: /.)

SSSE3vpermb / AVX1 yerine AVX512VBMI kullanmamın nedeni pshufbiki yönlüdür:

  • vpermbseçicilerin yüksek bitlerini yok sayar. (v)pshufbKontrol vektörünün yüksek bitine göre sıfır bayt ve bir pandveya andpsdaha çok nibbleları izole etmek için gerekli olurdu . XMM / 16 bayt boyutuyla, vpermbshuffle kontrol elemanlarının yalnızca düşük 4 bitine, yani [3:0]Intel'in Operasyon bölümündeki gösterimlerindeki bitlere bakar .
  • vpermbkarıştırılacak verileri (arama tablosu) bellek işlenen olarak alabilir. (v)pshufb'ın xmm / mem işleneni shuffle kontrol vektörüdür.

AVX512VBMI'nin yalnızca CannonLake / Ice Lake'te bulunduğunu unutmayın, bu nedenle muhtemelen bunu test etmek için Intel'in SDE'si gibi bir simülatöre ihtiyacınız vardır.


⭐ - güzel cevap için yıldız
alıyorsunuz

@ KamilKiełczewski: lol teşekkürler. Sayıları onaltılı olarak verimli bir şekilde dönüştürmek en sevdiğim şeylerden biri. Birkaç düzgün hile ve bit manipülasyonu için güzel bir kullanım durumudur.
Peter Cordes

3

Scala , 58 40 36 bayt

"%08X"format Integer.reverseBytes(_)

Çevrimiçi deneyin!

Hala an'in baytlarını tersine çevirmek için yerleşkeyi Intkullanır, ancak Onaltılı olarak formatbiçimlendirmek için kullanır Int. Aramaya gerek yok toHexString.

Parens kaldırıldı format. Bu artık argümanın dolaylı olarak kullanılarak alınabileceği anlamına geliyor _.


2

İleri (gforth) , 52 51 40 bayt

: f hex 0 4. do <# # # 0. #> type loop ;

Çevrimiçi deneyin!

Kod açıklaması

: f           \ start a new word definition
  hex         \ set the current base to base 16
  0           \ convert the input number to a double-cell integer
  4. do       \ start a counted loop from 0 to 3
    <# # #    \ start a formatted numeric string and move last 2 digits to format area
    0.        \ move remaining digits down the stack
    #>        \ delete top two stack value and convert format area to string
    type      \ output string
  loop        \ end loop
;             \ end word definition



2

Excel, 91 bayt

=RIGHT(DEC2HEX(A1,8),2)&MID(DEC2HEX(A1,8),5,2)&MID(DEC2HEX(A1,8),3,2)&LEFT(DEC2HEX(A1,8),2)

2

K4 , 12 11 bayt

Çözüm:

,/$|4_0x0\:

Örnekler:

q)k),/$|4_0x0\:304767
"7fa60400"
q)0W
"0004a67f"

Açıklama:

Sorunun tam olarak sorduğu soru:

,/$|4_0x0\: / the solution
      0x0\: / split to bytes
    4_      / drop first 4 bytes
   |        / reverse
  $         / convert to string
,/          / flatten

Notlar:

  • -1 bayt K4 sayı olarak bırakarak yani 4 bayt (32bit), varsayılan olarak uzun (64 bit) olan

🚀 cevabınız üstte
Kamil Kiełczewski

2

PHP , 31 bayt

<?=unpack(H8,pack(V,$argn))[1];

Çevrimiçi deneyin!

PHP'nin paketinden ve paketinden yararlanarak , imzasız girişi "32 bit küçük endian bayt sırası" biçiminde ( V) bir ikili dizeye ekler ve ardından "hex dizgisi, önce yüksek uç" biçimiyle ( ) paketinden çıkarır Hve sonucu yazdırırım.

Bu, PHP'nin yerleşiklerinin basit bir algoritma uygulamaktan daha kısa olduğu nadir durumlardan biri gibi görünüyor!


PHP'nin pack()/ unpack()fonksiyonlarının çoğu PHP projesinde ihtiyaç duyduğunuz 0 kez harika. Tebrikler, kullanımlarını buldunuz!
640KB

1

Kömür , 11 bayt

⪫⮌⪪﹪%08xN²ω

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı versiyonudur. Açıklama:

        N   Input as a number
   ﹪%08x    Format using literal string
  ⪪      ²  Split into pairs of characters
 ⮌          Reverse
⪫         ω Join
            Implicitly print

Python biçimlendirmesine başvurmadan 19 bayt:

⪫…⮌⪪⍘⁺X²¦³⁶N¹⁶¦²¦⁴ω

Çevrimiçi deneyin! Bağlantı, kodun ayrıntılı versiyonudur. Açıklama:

           N        Input as a number
     ⁺              Plus
       ²            Literal 2
      X             To power
         ³⁶         Literal 36
    ⍘               Convert to base
            ¹⁶      Literal 16
   ⪪           ²    Split into pairs of digits
  ⮌                 Reverse the list
 …               ⁴  Take the first 4 pairs
⪫                 ω Join together
                    Implicitly print

Answer cevabınız üstte
Kamil Kiełczewski


1

J , 10 bayt

8{._1{3!:3

Çevrimiçi deneyin!

Nasıl

3!:3burada altı çizili temsil için bir J "yabancı birleşimidir" . Yani, hex'e dönüştürmek için bir yerleşiktir. Ancak, çıktı istediğimiz gibi değil. Örneğin;

3!:3 (304767)

üretir:

e300000000000000
0400000000000000
0100000000000000
0000000000000000
7fa6040000000000

Diğer satırların anlamı, yukarıda bağlantı verdiğim doküman sayfasında açıklanmaktadır. Her durumda, son satırın ilk 8 karakterini istediğimiz açıktır.

_1{ son satırı al.

8{. ilk 8 karakterini alır.


🚀 cevabınız üstte
Kamil Kiełczewski


1

Windows Toplu İş, 90 bayt

@for /l %%x in (24,-8,0)do @set/aa=%1^>^>%%x^&255&cmd/cexit !a!&<nul set/p=!=exitcode:~-2!

Gecikmeli genişletmeyi etkinleştirmek için komut satırını / v ile çalıştırın.


1

x86 32 bit makine kodu, 24 21 bayt

changelog: -3 bytes: @peter ferrie tarafından standart add / cmp / jbe / add'i bir DAS hack'iyle değiştirin

64 bit: hala 24 bayt. Uzun mod, DAS op kodunu kaldırdı.
16 bit modu: varsayılan işlenen boyutu 16 bittir, ancak sorun özelliği doğal olarak 32 bittir. Sabit kodlu 8 onaltılık basamak dahil.


İle bayt ters bswapstandart amacıyla daha sonra elle int-> hex (en anlamlı yarım bayt ilk artan bir karakter çıkış tamponu hex basamak yazma.), Bir baytlık ve içinde yarım bayt arasında geçiş sırasına döngü göz önüne sermek için ihtiyaç duyan bu önüne geçilmesini bayt boyunca.

void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);64 bit modunda çalışmadığı sürece x86-64 System V gibi çağrılabilir . (EDI için çıkış işaretçisine ihtiyaç duyar stosb. Giriş numarası ECX veya EAX dışında herhangi bir kayıtta olabilir.)

     1                             lehex:
     2 00000000 0FCE                   bswap  esi
     3 00000002 6A08                   push   8            ; 8 hex digits
     4 00000004 59                     pop    ecx
     5                             .loop:                ;do{
     6 00000005 C1C604                 rol    esi, 4       ; rotate high nibble to the bottom
     7                             
     8 00000008 89F0                   mov    eax, esi
     9 0000000A 240F                   and    al, 0x0f     ; isolate low nibble
    10 0000000C 3C0A                   cmp al, 10          ; set CF according to digit <= 9
    11 0000000E 1C69                   sbb al, 0x69        ; read CF, set CF and conditionally set AF
    12 00000010 2F                     das                 ; magic, which happens to work
    13                             
    14 00000011 AA                     stosb               ; *edi++ = al
    15 00000012 E2F1                   loop  .loop       ; }while(--ecx)
    16                             
    17 00000014 C3                     ret

boyut = 0x15 = 21 bayt.

TIO FASM 32 bit x86 test durumu , write2 dizgiyi bir tampona eklemek için iki kez çağırdıktan sonra çıkışı yazmak için sistem çağrısı kullanan bir asm arayanı ile . Sayı ile harf arasındaki sınırda 9 ve A dahil olmak üzere 0..F tüm onaltılık basamakları test eder.

DASHack - x86 düşük dişlemesini dışarı taşınması için, yarım taşıma bayrağı vardır. İki 2 basamaklı BCD tamsayısının çıkarılmasından sonra kullanılması amaçlanan DAS talimatı gibi paketlenmiş BCD şeyler için kullanışlıdır. AL'nin düşük nibble'ı 0-9 aralığının dışında olduğunda, kesinlikle burada kötüye kullanıyoruz.

Kılavuzdaki Çalıştırma bölümünün if (old_AL > 99H) or (old_CF = 1)THEN AL ← AL − 60H;kısmına dikkat edin ; sbb her zaman CF'yi ayarlar, böylece kısım her zaman olur. Bu ve büyük harfler için ASCII aralığı,sub al, 0x69

  • cmp 0xD, 0xA CF ayarlamıyor
  • sbb 0xD - 0x69AL = 0xA4'ye girdi olarak DAS'a girdi. (Ve CF'yi ayarlar, AF'yi temizler)
  • DAS'ın ilk bölümünde AL - = 6 yok (çünkü 4> 9 yanlış ve AF = 0)
  • AL - = 0x60 ikinci bölümde, 0x44ASCII kodunu'D'

bir sayıya karşı:

  • cmp 0x3, 0xA CF setleri
  • sbb 3 - 0x69 - 1= AL = 0x99 ve CF ve AF'yi ayarlar
  • DAS'ın ilk bölümünde AL - = 6 yok (9> 9 yanlış ama AF ayarlanmış), 0x93 bırakarak
  • AL - = 0x60 ikinci bölümde, 0x33, ASCII kodu için bırakılır '3'.

SBB'den çıkarma 0x6a, her sayı için <= 9 AF ayarlayacaktır, böylece tüm sayılar aynı mantığı izler. Ve her alfabetik onaltılık basamak için boş bırakın. yani DAS'ın 9 / A ayrık kullanımından doğru bir şekilde yararlanmak.


Normalde (performans için) skaler döngü için bir arama tablosu veya muhtemelen dalsız 2x leave cmp/cmovkoşullu ekleme kullanırsınız. Ancak 2 baytlık al, imm8talimatlar, kod boyutu için büyük bir kazançtır.


x86-64 sürüm sürümü : and al, 0xfve arasında sadece farklı olan bölüm stosb.

;; x86-64 int -> hex  in 8 bytes
    10 0000000C 0430                   add    al, '0'
    11 0000000E 3C39                   cmp    al, '9'
    12 00000010 7602                   jbe  .digit
    13 00000012 0427                     add    al, 'a'-10 - '0'     ; al =  al>9 ? al+'a'-10 : al+'0'
    14                             .digit:

Bildirim o add al, '0' zaman çalışır ve koşullu eklenti sadece arasındaki farkı ekler 'a'-10ve '0'sadece bir bunu yapmak için, ifyerine if/ ' else.

Test edilmiş ve çalışır, Cmain yanıtımla aynı arayanı kullanır ve kullanır .char buf[8]printf("%.8s\n", buf)


Örneğin burada çevrimiçi çalışan snippet oluşturabilir misiniz ?
Kamil Kiełczewski

@ KamilKiełczewski: TIO, bir asm fonksiyonunu test etmek için arayanı C'ye yazmayı imkansız kılar, böylece sık sık rahatsız etmiyorum, ancak sys_writesabit uzunluklu dizeleri kolayca çıkardığınızdan ve çıkardığınızdan eminim . Çok ilginç, FIO'nun TIO'da fark etmediğini fark etmedim, NASM'den farklı olarak 32 bit yürütülebilir dosyalar oluşturmanıza izin vermedim -felf32. Zaten x86-64'ü tercih ediyorum ve bu cevap 32 bit koddan herhangi bir bayt kaydetmiyor.
Peter Cordes

⭐ - güzel cevap için yıldız
alıyorsunuz

1
@ JL2210: Bunu mu demek istediniz sprintf? Ben libc biçim-string tabanlı olanlar dışında, sadece string-> int strtoul gibi herhangi bir kullanışlı int-> string işlevleri olduğunu sanmıyorum. Ancak, dinamik bir kitaplıktaki (6 baytlık call [rel printf wrt ..got]çağrı sitesinin yanında) bir işlev için GOT girişi için bayt saymanın bir yolunu bulabilirseniz, bswap / printf muhtemelen daha kısa olacaktır ; en az statik olarak bağlı yürütülebilir dosyalar, en azından ldnormal varsayılanlarla yapıldığı zaman dinamikten önemli ölçüde daha küçük olabilir . Ama statik olarak bağlamak için makul olacağını sanmıyorum ama kod boyutunu saymak değil.
Peter Cordes

1
@ JL2210: Unutmayın, bu bir x86 makine kodu yanıtıdır, metin kaynak boyutu değil. Önceki makine kodu yanıtlarında libc işlevlerini, yalnızca Linux sistem çağrılarını (örneğin Fibonacci'de) ve IDK'yi maliyet sayma konusunda nasıl çalışacağımı veya hatta libc ile makine kodu kodu yazmak isteyip istemediğimi kullanmadım . X86 makine kodunun, örneğin bir önyükleyicide, bir libc'nin kullanılamadığı durumlarda kullanım örnekleri vardır.
Peter Cordes
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.