x86 kode mesin 32-bit, 24 21 byte
changelog: -3 byte: ganti add standar / cmp / jbe / add dengan hack DAS oleh @peter ferrie
64-bit: masih 24 byte. Mode lama menghapus opcode DAS.
Mode 16-bit: ukuran operan standar adalah 16-bit tetapi spesifikasi masalahnya pada dasarnya 32-bit. Termasuk hard-kode 8 digit hex.
Bolak-balik dengan bswapint-> manual kemudian hex dalam urutan standar (paling signifikan menggigit pertama, menulis digit hex ke buffer output char dalam urutan menaik). Ini menghindari perlu membuka gulungan untuk beralih urutan antara menggigit dalam byte vs melintasi byte.
Dapat dipanggil void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);seperti x86-64 Sistem V, kecuali ini tidak berfungsi dalam mode 64-bit. (Perlu pointer output di EDI untuk stosb. Nomor input dapat dalam register selain ECX atau EAX.)
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
size = 0x15 = 21 byte.
TIO FASM 32-bit kasus uji x86 dengan pemanggil asm yang menggunakan pemanggilan writesistem untuk menulis output setelah memanggilnya dua kali untuk menambahkan 2 string ke dalam buffer. Menguji semua digit hex 0..F, termasuk 9 dan A pada batas antara angka vs huruf.
The DAShack - x86 memiliki setengah-membawa bendera, untuk membawa keluar dari nibble rendah. Berguna untuk hal-hal BCD yang dikemas seperti instruksi DAS, dimaksudkan untuk digunakan setelah mengurangi dua bilangan bulat BCD 2 digit. Dengan nibble rendah AL yang berada di luar rentang 0-9, kami pasti menyalahgunakannya di sini.
Perhatikan if (old_AL > 99H) or (old_CF = 1)LALU AL ← AL − 60H;bagian dari bagian Operasi dalam manual; sbb selalu mengatur CF di sini sehingga bagian itu selalu terjadi. Itu dan kisaran ASCII untuk huruf besar adalah apa yang memotivasi pilihansub al, 0x69
cmp 0xD, 0xA tidak mengatur CF
- sbb
0xD - 0x69wraps ke AL = 0xA4sebagai input ke DAS. (Dan mengatur CF, menghapus AF)
- tidak ada AL - = 6 pada bagian pertama DAS (karena 4> 9 salah dan AF = 0)
- AL - = 0x60 di bagian kedua, meninggalkan
0x44, kode ASCII untuk'D'
vs. angka:
cmp 0x3, 0xA mengatur CF
- sbb
3 - 0x69 - 1= AL = 0x99 dan mengatur CF dan AF
- tidak ada AL - = 6 pada bagian pertama DAS (9> 9 salah tetapi AF diatur), meninggalkan 0x93
- AL - = 0x60 di bagian kedua, meninggalkan 0x33, kode ASCII untuk
'3'.
Mengurangkan 0x6adalam SBB akan menetapkan AF untuk setiap digit <= 9 sehingga semua angka mengikuti logika yang sama. Dan biarkan itu dibersihkan untuk setiap digit hex alfabet. yaitu dengan benar mengeksploitasi penanganan split 9 / A DAS.
Biasanya (untuk kinerja) Anda akan menggunakan tabel pencarian untuk loop skalar, atau mungkin 2x tanpa cabang leadan cmp/cmovtambahan bersyarat. Tetapi al, imm8instruksi 2-byte adalah kemenangan besar untuk ukuran kode.
versi versi x86-64 : hanya bagian yang berbeda, antara and al, 0xfdan 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:
Perhatikan bahwa add al, '0' selalu berjalan, dan penambahan bersyarat hanya menambahkan perbedaan antara 'a'-10dan '0', untuk membuatnya hanya sebagai ifpengganti if/ else.
Diuji dan berfungsi, menggunakan mainpenelepon yang sama dengan jawaban C saya , yang menggunakan char buf[8]dan printf("%.8s\n", buf).