x86 32ビットマシンコード、24 21バイト
変更ログ:-3バイト:標準のadd / cmp / jbe / addを@peter ferrieによるDASハックに置き換えます
64ビット:まだ24バイト。ロングモードはDASオペコードを削除しました。
16ビットモード:デフォルトのオペランドサイズは16ビットですが、問題の仕様は本質的に32ビットです。ハードコードされた8桁の16進数を含む。
bswap標準の順序で手動でint-> hexを使用してバイトを反転します(最上位ニブルを最初に、16進数をchar出力バッファーに昇順で書き込みます)。これにより、バイト内のニブル間の順序を切り替えるループを展開する必要がなくなりますバイト間。
void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);x86-64 System Vのように呼び出し可能ですが、これは64ビットモードでは機能しません。(EDIの出力ポインタが必要ですstosb。入力番号は、ECXまたは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
サイズ= 0x15 = 21バイト。
TIO FASM 32ビットx86テストケースで、writeシステムコールを使用して出力を2回呼び出してから2つの文字列をバッファーに追加した後、システムコールを使用して出力を書き込みます。数字と文字の境界で9とAを含むすべての16進数0..Fをテストします。
DASハック - x86の低ニブルのうちキャリーのために、ハーフキャリーフラグを持っています。2桁の2桁のBCD整数を減算した後の使用を目的とした、DAS命令などのパックドBCDに役立ちます。ALのニブルが0〜9の範囲外であるため、ここで間違いなく悪用しています。
マニュアルの操作セクションのif (old_AL > 99H) or (old_CF = 1)THEN AL ← AL − 60H;部分に注意してください。sbbは常に CFをここに設定するため、一部が常に発生します。それと大文字のASCII範囲は、選択の動機となるものですsub al, 0x69
cmp 0xD, 0xA CFを設定しません
- sbb
0xD - 0x69はAL =にラップします0xA4、DASへの入力としてます。(CFを設定し、AFをクリアします)
- DASの最初の部分にAL-= 6はありません(4> 9が偽でAF = 0であるため)
- AL-= 0x60の2番目の部分では
0x44、'D'
対数字:
cmp 0x3, 0xA CFを設定します
- sbb
3 - 0x69 - 1 = AL = 0x99およびCFとAFを設定
- DASの最初の部分にAL-= 6がありません(9> 9は偽ですが、AFは設定されています)、0x93を残します
- AL-= 2番目の部分の0x60。0x33のASCIIコードを残します
'3'。
0x6aSBBで減算すると、すべての数字が9以下のすべての数字にAFが設定されるため、すべての数字は同じ論理に従います。そして、アルファベットの16進数字ごとにクリアしたままにします。すなわち、DASの9 / A分割処理を正しく活用します。
通常(パフォーマンスのため)、スカラーループのルックアップテーブルを使用するか、場合によってはブランチレス2x leaおよびcmp/cmov条件付き追加を使用します。ただし、2バイトのal, imm8命令は、コードサイズにとって大きなメリットです。
x86-64バージョンversion:との間and al, 0xfで異なる部分のみ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:
通知はことをadd al, '0' 常に実行され、条件付きaddは唯一の違いを追加'a'-10して'0'、それだけで作ることifの代わりにif/else。
テストおよび作品、それを用いmainて、発信者を私のCの答えは使用しています、char buf[8]とprintf("%.8s\n", buf)。