Código de máquina x86 de 32 bits, 24 21 bytes
registro de cambios: -3 bytes: reemplace add / cmp / jbe / add estándar con un hack de DAS por @peter ferrie
64 bits: todavía 24 bytes. El modo largo eliminó el código de operación DAS.
Modo de 16 bits: el tamaño de operando predeterminado es de 16 bits, pero la especificación del problema es inherentemente de 32 bits. Incluidos 8 dígitos hexadecimales codificados.
Byte-reverse con bswap
luego manual int-> hex en orden estándar (el mordisco más significativo primero, escribiendo dígitos hexadecimales en un buffer de salida de caracteres en orden ascendente). Esto evita la necesidad de desenrollar el bucle para cambiar el orden entre mordiscos dentro de un byte vs. a través de bytes.
Se puede llamar como void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);
x86-64 System V, excepto que esto no funciona en modo de 64 bits. (Necesita el puntero de salida en EDI para stosb
. El número de entrada puede estar en cualquier registro que no sea ECX o 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
tamaño = 0x15 = 21 bytes.
TIO FASM Caso de prueba x86 de 32 bits con una llamada asm que utiliza una write
llamada al sistema para escribir la salida después de llamarla dos veces para agregar 2 cadenas a un búfer. Prueba todos los dígitos hexadecimales 0..F, incluidos 9 y A en el límite entre el número y la letra.
El DAS
hack - x86 tiene una bandera de medio acarreo, para llevar a cabo el mordisco bajo. Útil para cosas BCD empaquetadas como la instrucción DAS, pensadas para usar después de restar dos enteros BCD de 2 dígitos. Con el mordisco bajo de AL estando fuera del rango 0-9, definitivamente estamos abusando de esto aquí.
Observe if (old_AL > 99H) or (old_CF = 1)
ENTONCES la AL ← AL − 60H;
parte de la sección Operación en el manual; sbb siempre establece CF aquí para que esa parte siempre suceda. Eso y el rango ASCII para letras mayúsculas es lo que motiva la elección desub al, 0x69
cmp 0xD, 0xA
no establece CF
- sbb se
0xD - 0x69
ajusta a AL = 0xA4
como entrada a DAS. (Y establece CF, borra AF)
- no AL - = 6 en la primera parte de DAS (porque 4> 9 es falso y AF = 0)
- AL - = 0x60 en la segunda parte, dejando
0x44
, el código ASCII para'D'
contra un número:
cmp 0x3, 0xA
establece CF
- sbb
3 - 0x69 - 1
= AL = 0x99 y establece CF y AF
- no AL - = 6 en la primera parte de DAS (9> 9 es falso pero AF está configurado), dejando 0x93
- AL - = 0x60 en la segunda parte, dejando 0x33, el código ASCII para
'3'
.
Restar 0x6a
en SBB establecerá AF para cada dígito <= 9, por lo que todos los números siguen la misma lógica. Y déjelo despejado para cada dígito hexadecimal alfabético. es decir, explotar correctamente el manejo dividido 9 / A de DAS.
Normalmente (para el rendimiento) usaría una tabla de búsqueda para un bucle escalar, o posiblemente un 2x sin ramificaciones lea
y una cmp/cmov
adición condicional. Pero las al, imm8
instrucciones de 2 bytes son una gran victoria para el tamaño del código.
Versión de la versión x86-64 : solo la parte que es diferente, entre and al, 0xf
y 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:
Tenga en cuenta que add al, '0'
siempre se ejecuta, y el complemento condicional solo agrega la diferencia entre 'a'-10
y '0'
, para que sea solo un en if
lugar de if
/ else
.
Probado y funciona, usando la misma main
llamada que mi respuesta C , que usa char buf[8]
y printf("%.8s\n", buf)
.
f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)
guarda un byte :)