Conversione da numero Little Endian a stringa


13

introduzione

Durante il lavoro con il generatore BMP (bitmap) ho riscontrato problemi nella conversione di numeri in stringhe esadecimali di piccole dimensioni. Ecco la funzione che creo in JavaScript, ma mi chiedo come il piccolo codice possa funzionare in modo simile

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

Sfida

Scrivi la funzione che prenderà un numero intero senza segno a 32 bit sull'input e produrrà una stringa esadecimale a 8 cifre con un piccolo ordine endiano. L'algoritmo di esempio che fa il lavoro:

  • converti intorpidimento in stringa esadecimale, ad esempio: 304767 -> '4a67f'
  • aggiungi zeri di riempimento per ottenere una stringa da 8 caratteri: '0004a67f'
  • dividere la stringa in quattro pezzi da 2 caratteri: '00','04','a6','7f'
  • ordine inverso dei pezzi '7f','a6','04','00'
  • unisci i pezzi e ritorna come risultato: '7fa60400'

Esempio di input e output

Il numero di input (o stringa con numero dec) è a sinistra di ->, la stringa esadecimale di output è a destra

2141586432 -> 0004a67f
304767     -> 7fa60400

Risposte:


7

05AB1E , 10 9 byte

žJ+h¦2ôRJ

Provalo online!

-1 byte per ispirazione della risposta Jelly.

ž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 byte

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

Provalo online!

Soluzione ricorsiva basata sull'aritmetica ( 50 49 byte, funziona anche per Python 2 ) :

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

Provalo online!

-1 byte grazie a @JonathanAllan


Direi di inviare quello ricorsivo come voce di Python 2 :)
Jonathan Allan,

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

@JonathanAllan Grazie. Non ho familiarità con tutti i trucchi di Python 2 e non vedo come possa essere abbreviato.
Joel

non funziona, ma il 37 non funzionerà in 2
Jonathan Allan,

Si. Alcuni di questi built-in sono solo Python-3.
Joel

6

R , 54 53 byte

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

Provalo online!

Ogni gruppo di 2 caratteri è in realtà la rappresentazione esadecimale di una cifra nella base 256. scan()%/%256^(0:3)%%256converte in un numero base 256 con 4 cifre invertite, le ...%*%256^(3:0)unisce come un unico numero intero e format.hexmode(...,8)converte quel numero nella sua rappresentazione esadecimale con 8 cifre.


5

JavaScript (ES7),  59  57 byte

Manipolazione di stringhe.

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

Provalo online!

Come?

Per prima cosa convertiamo in esadecimali per assicurarci che siano inclusi tutti gli iniziali:n+2320

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

Provalo online!

Usiamo l'espressione regolare /\B../gper abbinare tutti i gruppi di 2 cifre, ignorando il grazie a ( confine non di parole ).1\B

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

Provalo online!

Noi reverse()e join()per ottenere la stringa finale.


JavaScript (ES6), 61 byte

Funzione ricorsiva.

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

Provalo online!


⭐ - ottieni una stella per una bella risposta - Mi piace, breve ma ancora pulito e "redable umano" :)
Kamil Kiełczewski


5

C # (compilatore interattivo Visual C #) , 54 byte

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

Salvato 4 byte grazie a @PeterCordes

Provalo online!

Spiegazione

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

È possibile ridurre la 4278255360costante di maschera su 16711935( 0xff00ff) se si sposta prima del mascheramento? O questo costa genitori extra? Inoltre, se non 0xff00ff00è allora la stessa lunghezza ma molto più significativa per gli umani.
Peter Cordes,

@PeterCordes Ha anche il vantaggio di essere in grado di rimuovere le parentesi poiché >>ha una precedenza maggiore rispetto a &, con un totale di 4 byte salvati. Grazie!
Incarnazione dell'ignoranza,

Freddo. Nella sezione "spiegazione", suggerirei di scrivere le costanti in esadecimale.
Peter Cordes,

4

Japt -P , 10 byte

sG ùT8 ò w

Provalo

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

Cosa fa -P?
SS Anne

🚀 la tua risposta è in alto (puoi aggiungere una spiegazione?)
Kamil Kiełczewski

@ JL2210 Dai documenti : " -P: Se l'output è un array, output senza separatore (ovvero uniti con P). ". Quindi il flag è per un join implicito anziché esplicito per salvare byte. :)
Kevin Cruijssen,

2
@ KamilKiełczewski, spiegazione aggiunta.
Shaggy,


4

Python 2 , 43 byte

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

Provalo online!

-4 byte grazie a benrg

Emette un elenco di caratteri. Calcolato recuperando, in ordine, le cifre esadecimali dell'input negli indici 6, 7, 4, 5, 2, 3, 0, 1.


2
[i^6]for i in range(8)salva qualche byte.
ben

È consentito l'output dell'elenco anziché la stringa?
Qwertiy,

l'output come elenco non è realmente adatto allo spirito della domanda imo
qwr

3

C (gcc) endian agnostico, nessuna libreria standard, 92 91 byte

h(n)è una funzione di aiuto esagono intero a cifra singola-> esadecimale.
f(x,p)accetta un numero intero e un char[8]puntatore. Il risultato è 8 byte di chardati. ( Non terminato con 0 se il chiamante non lo fa.)

Presupposti: set di caratteri ASCII. Il complemento di 2, intquindi lo spostamento a destra alla fine abbassa il bit del segno e la conversione di uint32_ta intnon modifica il bit-pattern se il bit alto è impostato. intè almeno a 32 bit. (Più ampio potrebbe lasciarlo funzionare sulle implementazioni del complemento 1 o della grandezza del segno 1).

Non assunzioni: qualsiasi cosa sull'implementazione dell'ordine dei byte o la firma di 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);}

Provalo online! incluso il chiamante di prova che utilizza printf("%.8s\n", buf)per stampare il buffer di output senza terminarlo con 0.

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);
}

Fare n&=15;dentro h(x)è in pareggio; 6 byte lì contro 3 ciascuno per &15isolare il bocconcino basso in entrambi i siti di chiamata.

,è un punto di sequenza (o equivalente nella terminologia moderna), quindi è sicuro fare *p++= stuffdue volte in una frase una volta separato ,dall'operatore.

>>sull'intero con segno è definito dall'implementazione come aritmetico o logico. GNU C lo definisce come complemento aritmetico 2. Ma su qualsiasi complemento a 2 non importa davvero perché non guardiamo mai gli 0 spostati o le copie del bit di segno. L'MSB originale alla fine scenderà invariato nel byte basso. Questo non è il caso di segno / magnitudo e non sono sicuro del complemento di 1.

Quindi questo può essere portatile solo per le implementazioni C del complemento di 2. (O dove intè più largo di 32 bit, quindi il bit 31 è solo una parte della grandezza.) Unsigned -> la conversione con segno muta anche il modello di bit per gli interi negativi, così &15da intestrarre solo nibble del valore originale senza segno sul complemento di 2. Ancora una volta, a meno che non intfosse più largo di 32 bit, quindi tutti gli ingressi sono non negativi.

La versione giocata a golf ha UB dalla caduta di una funzione non nulla. Non restituire un valore, solo per evitare di dichiararlo voidinvece di default int. I compilatori moderni romperanno questo con l'ottimizzazione attivata.


Motivazione: Stavo prendendo in considerazione una risposta asm x86 o ARM Thumb, ho pensato che sarebbe stato divertente farlo manualmente in C, forse per asm generato dal compilatore come punto di partenza. Vedi /programming/53823756/how-to-convert-a-number-to-hex per l'asm x86 ad alta velocità, inclusa una versione AVX512VBMI che è solo 2 istruzioni (ma necessita di vettori di controllo per vpmultishiftqb e vpshufb quindi non sarebbe fantastico per il golf). Normalmente ci vuole un lavoro extra per SIMD per invertire byte nell'ordine di stampa su x86 little-endian, quindi questo output esadecimale con byte invertiti è in realtà più semplice del normale.


Altre idee

Ho considerato di prendere l'intero come riferimento e di eseguire il looping dei suoi byte con char*, su un'implementazione C little-endian (come x86 o ARM). Ma non penso che avrebbe risparmiato molto.

Usando sprintfper fare 1 byte alla volta, 64 byte dopo il golf:

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

Ma se stiamo usando funzioni simili a printf, potremmo anche scambiare byte e fare una %xstampa di tutto come la risposta di @ JL2210 .


⭐ - ottieni una stella per una bella risposta
Kamil Kiełczewski

3

x86 Codice macchina SIMD (AVX512-VBMI), 36 byte

(16 byte di cui sono una tabella di ricerca esadecimale)

Questa è una funzione che accetta un numero intero xmm0e restituisce 8 byte di dati char ASCII xmm0, affinché il chiamante possa archiviare dove vuole. (ad es. alla memoria video dopo l'interlacciamento con byte di attributo o in una stringa in costruzione o altro)

Da C, chiamalo come __m128i retval = lehex(_mm_cvtsi32_si128(x))con la convenzione di chiamata System V x86-64 o MS Windows 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"

Totale = 0x24 = 36 byte.

Vedi Come convertire un numero in esadecimale? su SO per come funziona. (SSE2 per shift / punpck, quindi vpermbsalva il lavoro di cui avremmo bisogno pshufb. AVX1 invece di SSE2 / SSSE3 evita anche una movapscopia del registro.)

Si noti che punpcklbwcon gli operandi di origine in questo ordine ci fornirà il nibble più significativo del byte di input basso nell'elemento byte più basso, quindi il nibble meno significativo del byte di origine più basso. (In quella risposta SO, a bswapviene utilizzato un input per ottenere un risultato nell'ordine di stampa standard con solo SSE2. Ma qui vogliamo quell'ordine: nibble alto nell'elemento inferiore all'interno di ogni byte, ma ancora ordine byte little-endian).

Se avessimo più costanti di dati, potremmo risparmiare spazio nella modalità di indirizzamento eseguendone una, mov edx, imm32quindi utilizzando [rdx+16]o qualunque modalità di indirizzamento. Or vpbroadcastb xmm0, [rdx+1].

Ma penso che un LUT + esadecimale da 16 byte vpermbsia ancora meglio dell'implementazione della n>9 : n+'a'-10 : n+'0'condizione: ciò richiede 3 costanti e almeno 3 istruzioni con mascheramento byte AVX512BW (confronta in maschera vpaddb, unione-mascherato vpaddb) o più con AVX1 o SSE2. (Vedi Come convertire un numero in esadecimale? Su SO per una versione SSE2 di quello). E ogni istruzione AVX512BW è lunga almeno 6 byte (EVEX a 4 byte + opcode + modrm), più lunga con uno spostamento nella modalità di indirizzamento.

In realtà, occorrerebbero almeno 4 istruzioni perché prima di eseguire il confronto è necessario eliminare la spazzatura elevata con andps(o EVEX vpanddcon un operando di memoria di trasmissione a 4 byte). E ognuno di questi ha bisogno di una costante vettoriale diversa. AVX512 ha operandi di memoria broadcast, ma solo per elementi di 32 bit e più ampi. es . l'ultimo operando di EVEXvpaddb è solo xmm3/m128, no xmm3/m128/m8bcst. (Le porte di carico di Intel possono eseguire gratuitamente solo trasmissioni a 32 e 64 bit come parte di un caricamento in modo che Intel abbia progettato AVX512BW per riflettere ciò e non essere in grado di codificare affatto operandi di memoria di trasmissione di byte o parole, invece di dare loro l'opzione di eseguire trasmissioni di dword in modo da poter ancora comprimere le costanti in 4 byte: /.)

Il motivo per cui ho usato AVX512VBMIvpermb invece di SSSE3 / AVX1 pshufbè duplice:

  • vpermbignora i bit alti dei selettori. (v)pshufbzeri byte in base al bit alto del vettore di controllo e avrebbero avuto bisogno di un extra pando andpsdi isolare effettivamente i nibble. Con una dimensione XMM / 16 byte, vpermbesamina solo i 4 bit bassi degli elementi di controllo shuffle, ovvero i bit [3:0]nella notazione Intel nella sezione Funzionamento .
  • vpermbpuò prendere i dati da mescolare (la tabella di ricerca) come operando di memoria. (v)pshufbL 'operando xmm / mem è il vettore di controllo shuffle.

Nota che AVX512VBMI è disponibile solo su CannonLake / Ice Lake, quindi probabilmente avrai bisogno di un simulatore per testarlo, come Intel SDE.


⭐ - ottieni una stella per una bella risposta
Kamil Kiełczewski,

@ KamilKiełczewski: lol grazie. Convertire i numeri in esadecimale in modo efficiente è una delle mie cose preferite. È un bel caso d'uso per diversi trucchi e manipolazione dei bit.
Peter Cordes,

3

Scala , 58 40 36 byte

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

Provalo online!

Usa ancora il builtin per invertire i byte di un Int, ma usa formatper formattare Intcome esadecimale. Non c'è bisogno di chiamare toHexString.

Rimosse le parentesi format. Questo ora significa che l'argomento può essere preso implicitamente usando _.


2

Forth (gforth) , 52 51 40 byte

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

Provalo online!

Spiegazione del codice

: 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 byte

=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 byte

Soluzione:

,/$|4_0x0\:

Esempi:

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

Spiegazione:

Praticamente esattamente cosa pone la domanda:

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

Appunti:

  • -1 byte poiché i numeri K4 sono lunghi (64 bit) per impostazione predefinita, quindi eliminando 4 byte (32 bit)

🚀 la tua risposta è in alto
Kamil Kiełczewski il

2

PHP , 31 byte

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

Provalo online!

Sfruttando il pacchetto di PHP e decomprimendo , comprimo l'input senza segno con il formato "ordine bit byte endian a 32 bit" ( V) in una stringa binaria e quindi scompattalo con il formato "stringa esadecimale, nibble alto primo" ( H) e stampo il risultato.

Questo sembra essere uno dei rari casi in cui i built-in di PHP sono in realtà più brevi rispetto all'implementazione di un semplice algoritmo!


Le funzioni pack()/ PHP unpack()sono fantastiche per le 0 volte in cui ne hai mai avuto bisogno nella maggior parte dei progetti PHP. Complimenti, hai trovato il loro uso!
640 KB

1

Carbone , 11 byte

⪫⮌⪪﹪%08xN²ω

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

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

19 byte senza ricorrere alla formattazione di Python:

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

Provalo online! Il collegamento è alla versione dettagliata del codice. Spiegazione:

           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

🚀 la tua risposta è in alto
Kamil Kiełczewski


1

J , 10 byte

8{._1{3!:3

Provalo online!

Come

3!:3è una "congiunzione straniera" J per la rappresentazione esadecimale, documentata qui . Cioè, è un builtin per la conversione in esadecimale. Tuttavia, non è esattamente quello che vogliamo. Ad esempio, in esecuzione:

3!:3 (304767)

produce:

e300000000000000
0400000000000000
0100000000000000
0000000000000000
7fa6040000000000

Il significato delle altre righe è spiegato nella pagina del documento a cui ho collegato sopra. In ogni caso, è chiaro che vogliamo i primi 8 caratteri dell'ultima riga.

_1{ ottieni l'ultima riga.

8{. ne ottiene i primi 8 caratteri.


🚀 la tua risposta è in alto
Kamil Kiełczewski il

1

Rubino , 31 27 byte

Finì per essere una porta della risposta PHP di Night2 perché Ruby ha la stessa funzionalità pack / unpack.

->*i{i.pack(?V).unpack'H8'}

Provalo online!

La mia risposta originale a 31 byte che non ha sfruttato la modalità di decompressione di H8 perché non lo sapevo:

->*i{'%02x'*4%i.pack(?V).bytes}

Provalo online!


1

Lotto di Windows, 90 byte

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

Eseguire la riga di comando con / v per abilitare l'espansione ritardata.


1

x86 codice macchina a 32 bit, 24 21 byte

log delle modifiche: -3 byte: sostituisce standard add / cmp / jbe / add con un hack DAS di @peter ferrie

64 bit: ancora 24 byte. La modalità lunga ha rimosso il codice operativo DAS.
Modalità a 16 bit: la dimensione dell'operando predefinita è 16 bit ma la specifica del problema è intrinsecamente a 32 bit. Comprese 8 cifre esadecimali codificate.


Byte-reverse con bswapquindi int-> hex manuale in ordine standard (prima lo stuzzichino più significativo, scrivendo cifre esadecimali su un buffer di output caratteri in ordine crescente). Questo evita di dover srotolare il loop per cambiare l'ordine tra i nibble all'interno di un byte vs. attraverso byte.

Callable void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);come x86-64 System V, tranne che non funziona in modalità 64-bit. (È necessario il puntatore di output in EDI per stosb. Il numero di input può trovarsi in qualsiasi registro diverso da 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

dimensione = 0x15 = 21 byte.

Caso di prova x86 TIO FASM a 32 bit con un chiamante asm che utilizza una writechiamata di sistema per scrivere l'output dopo averlo chiamato due volte per aggiungere 2 stringhe in un buffer. Verifica tutte le cifre esadecimali 0..F, inclusi 9 e A al confine tra numerale e lettera.

L' DAShacking - x86 ha una bandiera half-carry, per eseguire il nibble basso. Utile per oggetti BCD confezionati come l'istruzione DAS, destinati all'uso dopo aver sottratto due numeri interi BCD a 2 cifre. Con il basso bocconcino di AL che è al di fuori dell'intervallo 0-9, qui stiamo sicuramente abusando.

Si noti la parte if (old_AL > 99H) or (old_CF = 1)THEN AL ← AL − 60H;della sezione Operation del manuale; sbb imposta sempre CF qui in modo che la parte accada sempre. Questo e l'intervallo ASCII per le lettere maiuscole è ciò che motiva la scelta disub al, 0x69

  • cmp 0xD, 0xA non imposta CF
  • sbb esegue il 0xD - 0x69wrapping su AL = 0xA4come input per DAS. (E imposta CF, cancella AF)
  • no AL - = 6 nella prima parte di DAS (perché 4> 9 è falso e AF = 0)
  • AL - = 0x60 nella seconda parte, lasciando 0x44, il codice ASCII per'D'

vs. un numero:

  • cmp 0x3, 0xA imposta CF
  • FFS 3 - 0x69 - 1= AL = 0x99 e schede CF e AF
  • no AL - = 6 nella prima parte di DAS (9> 9 è falso ma AF è impostato), lasciando 0x93
  • AL - = 0x60 nella seconda parte, lasciando 0x33, il codice ASCII per '3'.

La sottrazione 0x6ain FFS imposta AF per ogni cifra <= 9, quindi tutti i numeri seguono la stessa logica. E lascialo deselezionato per ogni cifra alfabetica esadecimale. cioè sfruttando correttamente la gestione suddivisa in 9 / A di DAS.


Normalmente (per le prestazioni) useresti una tabella di ricerca per un ciclo scalare, o possibilmente un 2x senza rami leae cmp/cmovun'aggiunta condizionale. Ma le al, imm8istruzioni a 2 byte sono una grande vittoria per la dimensione del codice.


versione x86-64 : solo la parte diversa, tra and al, 0xfe 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:

Si noti che viene add al, '0' sempre eseguito e l'aggiunta condizionale aggiunge solo la differenza tra 'a'-10e '0', per renderlo solo un ifinvece di if/ else.

Testato e funzionante, usando lo stesso mainchiamante della mia risposta C , che usa char buf[8]e printf("%.8s\n", buf).


puoi creare uno snippet funzionante online, ad esempio qui ?
Kamil Kiełczewski,

@ KamilKiełczewski: TIO rende impossibile (AFAIK) scrivere il chiamante in C per testare una funzione asm, quindi spesso non mi preoccupo, ma certo dal momento che hai chiesto e sys_writepuoi produrre facilmente stringhe di lunghezza fissa. Oh interessante, non avevo capito che FASM su TIO ti consentiva di creare eseguibili a 32 bit, a differenza del NASM dove non rispetta -felf32. Preferisco comunque x86-64 e questa risposta non salva alcun byte dal codice a 32 bit.
Peter Cordes,

⭐ - ottieni una stella per una bella risposta
Kamil Kiełczewski

1
@ JL2210: vuoi dire sprintf? Non credo che libc abbia utili funzioni int-> string diverse da quelle basate su string di formato, solo string-> int come strtoul. Ma sì, bswap / printf sarebbe probabilmente più breve, se riesci a trovare un modo per contare i byte per la voce GOT per una funzione in una libreria dinamica (oltre al call [rel printf wrt ..got]sito di chiamata a 6 byte ); un minimo eseguibile collegato staticamente può essere significativamente più piccolo di dinamico, almeno se realizzato ldcon valori predefiniti normali. Ma non penso che sarebbe ragionevole collegarlo staticamente ma non contare le dimensioni del suo codice.
Peter Cordes,

1
@ JL2210: Ricorda, questa è una risposta del codice macchina x86 , non una dimensione di origine del testo. Non ho usato le funzioni libc nelle precedenti risposte del codice macchina, solo chiamate di sistema Linux (ad es. In Fibonacci) e IDK come farei per contare il costo o se voglio persino scrivere risposte macchina-codice-con-libc . Ci sono casi d'uso per il codice macchina x86 in cui non è disponibile una libc, ad esempio in un bootloader.
Peter Cordes,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.