리틀 엔디안 수에서 문자열로 변환


13

소개

BMP (비트 맵) 생성기로 작업하는 동안 숫자를 리틀 엔디 언 16 진수 문자열로 변환하는 데 문제가 있습니다. 여기 JavaScript로 만든 함수가 있지만 작은 코드가 어떻게 비슷하게 작동하는지 궁금합니다.

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

도전

입력시 32 비트 부호없는 정수를 취하고 엔디안 순서가 거의없는 8 자리 16 진수 문자열을 생성하는 쓰기 기능. 작업을 수행하는 알고리즘 예 :

  • 마비를 16 진 문자열로 변환 예 : 304767 -> '4a67f'
  • 8 문자 문자열을 얻으려면 채우기 0을 추가하십시오. '0004a67f'
  • 줄을 4 개의 2 자리 조각으로 나누십시오. '00','04','a6','7f'
  • 조각의 역순 '7f','a6','04','00'
  • 조각을 결합하고 결과로 반환 : '7fa60400'

입력 및 출력 예

입력 번호 (또는 12 ->진수 문자열)는 왼쪽에 있고 출력 16 진 문자열은 오른쪽에 있습니다.

2141586432 -> 0004a67f
304767     -> 7fa60400

답변:



6

파이썬 3 , 37 바이트

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

온라인으로 사용해보십시오!

산술 기반 재귀 솔루션 ( 50 49 바이트, Python 2 에서도 작동 ) :

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

온라인으로 사용해보십시오!

@JonathanAllan 덕분에 -1 바이트


나는 :) 파이썬 2 항목으로 재귀 일 제출 말할 것
조나단 앨런

f=lambda n,i=4:i*'1'and'%02x'%(n%256)+f(n>>8,i-1)바이트를 저장합니다 :)
Jonathan Allan

@JonathanAllan 감사합니다. 나는 모든 Python 2 트릭에 익숙하지 않으며 어떻게 짧아 질 수 있는지 알지 못합니다.
Joel

그렇지 않습니다하지만 37 평 2에서 작동하지 않습니다
조나단 앨런

네. 이러한 내장 기능 중 일부는 Python-3 전용입니다.
Joel

6

R , 54 53 바이트

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

온라인으로 사용해보십시오!

2 개의 문자로 구성된 각 그룹은 실제로 기본 256의 숫자를 16 진수로 표현한 것입니다. scan()%/%256^(0:3)%%2564 자리 숫자를 거꾸로 한 기본 256 숫자로 변환 ...%*%256^(3:0)하고 단일 정수 format.hexmode(...,8)로 결합한 다음 해당 숫자를 8 자리의 16 진수 표현으로 변환합니다.


5

자바 스크립트 (ES7),  59  57 바이트

문자열 조작.

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

온라인으로 사용해보십시오!

어떻게?

먼저 모든 선행 이 포함 되도록 를 16 진수 로 변환합니다 .n+2320

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

온라인으로 사용해보십시오!

정규 표현식 /\B../g을 사용하여 2 자리의 모든 그룹을 일치 시키고 ( 단어가 아닌 경계 ) 덕분에 선행 무시합니다 .1\B

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

온라인으로 사용해보십시오!

우리 reverse()와는 join()최종 문자열을 얻을 수 있습니다.


자바 스크립트 (ES6), 61 바이트

재귀 기능.

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

온라인으로 사용해보십시오!


⭐-당신은 좋은 대답을 위해 별을 얻습니다-나는 그것을 좋아하지만 짧지 만 여전히 깨끗하고 "인간 가능":)
Kamil Kiełczewski


5

C # (Visual C # 대화식 컴파일러) , 54 바이트

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

@PeterCordes 덕분에 4 바이트 절약

온라인으로 사용해보십시오!

설명

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

마스킹 전에 이동하면 4278255360마스크 상수를 16711935( 0xff00ff)로 축소 할 수 있습니까 ? 아니면 추가 비용이 듭니까? 또한, 그렇지 않다면 길이는 같지만 인간에게는 훨씬 더 의미가 있습니다. 0xff00ff00
Peter Cordes

@PeterCordes 또한 총 4 바이트를 절약 한 >>것보다 우선 순위가 높은 대괄호를 제거 할 수 있다는 이점도 &있습니다. 감사!
무지의 구현

멋있는. "설명"섹션에서 상수를 16 진수로 작성하는 것이 좋습니다.
Peter Cordes

4

Japt -P , 10 바이트

sG ùT8 ò w

시도 해봐

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

무엇을 -P합니까?
SS Anne

🚀 귀하의 답변이 상단에 있습니다 (설명을 추가해 주시겠습니까?)
Kamil Kiełczewski

@ JL2210 문서에서 : " -P: 출력이 배열 인 경우 구분 기호없이 (즉,으로 결합 됨 P) 출력합니다. ". 따라서 플래그는 바이트를 절약하기 위해 명시 적 조인 대신 암시 적입니다. :)
Kevin Cruijssen

2
@ KamilKiełczewski, 설명이 추가되었습니다.
Shaggy


4

파이썬 2 , 43 바이트

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

온라인으로 사용해보십시오!

benrg 덕분에 -4 바이트

문자 목록을 출력합니다. indices에서 입력의 16 진수를 순서대로 검색하여 계산합니다 6, 7, 4, 5, 2, 3, 0, 1.


2
[i^6]for i in range(8)몇 바이트를 절약합니다.
benrg

문자열 대신 목록을 출력 할 수 있습니까?
Qwertiy

목록으로 출력은 실제로 질문 imo의 정신에 맞지 않습니다
qwr

3

C (gcc) 엔디안 불가지론, 표준 라이브러리 없음, 92 91 바이트

h(n)한 자리 정수-> 16 진 도우미 함수입니다.
f(x,p)정수와 char[8]포인터를받습니다. 결과는 8 바이트의 char데이터입니다. ( 아니 호출자가 작업을 수행하지 않는 한 0-종료되었습니다.)

가정 : ASCII 문자 세트. 2의 보수 int이므로 올바른 시프트는 결국 부호 비트를 낮추고 , 높은 비트가 설정되어 있으면 a uint32_t를 변환 int해도 비트 패턴이 바뀌지 않습니다. int32 비트 이상입니다. (Wider는 1의 보수 또는 부호 크기 C 구현에서 작동하게 할 수 있습니다).

비 가정 :의 구현 바이트 순서 또는 부호에 관한 모든 것 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);}

온라인으로 사용해보십시오! printf("%.8s\n", buf)출력 버퍼를 0으로 종료하지 않고 인쇄 하는 데 사용 하는 테스트 호출자 포함 .

언 골프 드 :

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

이렇게 n&=15;안쪽은 h(x)손익분기이다; &15두 호출 사이트에서 낮은 니블을 분리 하기 위해 각각 6 바이트와 3 바이트 .

,는 시퀀스 포인트 (또는 현대 용어와 동일)이므로 연산자로 *p++= stuff구분할 때 한 명령문에서 두 번 수행하는 것이 안전합니다 ,.

>>부호있는 정수에서 구현은 산술 또는 논리로 정의됩니다. GNU C는 이것을 산술 2의 보수로 정의합니다. 그러나 2의 보수 기계에서는 시프트 된 0 또는 부호 비트의 사본을 보지 않기 때문에 실제로 중요하지 않습니다. 원래 MSB는 결국 낮은 바이트로 변경되지 않습니다. 이것은 부호 / 크기의 경우가 아니며 1의 보수에 대해 확실하지 않습니다.

따라서 이것은 2의 보수 C 구현에만 이식 가능합니다. (여기서 또는 int이다 넓은 .보다 32 비트이므로 31 크기의 단지 일부 비트) 부호없는 -> 부호 변환도 munges 그래서 음수 대 비트 패턴 &15int단지 2의 보수의 원래 부호 값 니블을 추출한다. 다시 않는 int이었다 넓은 입력이 모두 음수가되도록보다 32 비트.

골프 버전은 UB가 비 공백 기능의 끝에서 떨어집니다. voiddefault 대신 선언하지 않도록 값을 반환하지 마십시오 int. 최신 컴파일러는 최적화가 활성화 된 상태에서이를 중단합니다.


동기 부여 : 나는 x86 또는 ARM Thumb asm 응답을 고려하고 있었고 C에서 수동으로 수행하는 것이 재미있을 수 있다고 생각했습니다. 아마도 컴파일러 생성 asm을 시작점으로 생각했을 수도 있습니다. 2 개의 명령 만있는 AVX512VBMI 버전을 포함하여 속도 효율적인 x86 asm 은 /programming/53823756/how-to-convert-a-number-to-hex 를 참조 하십시오 ( 단, vpmultishiftqb 및 vpshufb에 대한 제어 벡터가 필요함) 골프에는 좋지 않습니다). 일반적으로 리틀 엔디안 x86에서 SIMD가 인쇄 순서로 바이트 역전 되려면 추가 작업이 필요하므로이 바이트 역전 된 16 진 출력은 실제로 일반보다 쉽습니다.


다른 아이디어

char*리틀 엔디안 C 구현 (x86 또는 ARM과 같은)에서 참조로 정수를 가져 와서 바이트를 반복하는 것을 고려했습니다 . 그러나 나는 그것이 많은 것을 구했을 것이라고 생각하지 않습니다.

sprintf골프 후 64 바이트로 한 번에 1 바이트를 수행하는 데 사용 :

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

그러나 우리가 printf와 같은 기능을 사용한다면 @ JL2210의 답변%x 과 같은 모든 것을 바이트 스왑하고 printf 할 수 있습니다 .


⭐ - 당신은 좋은 답변 스타 얻을
카밀 Kiełczewski

3

x86 SIMD 머신 코드 (AVX512-VBMI), 36 바이트

(16 바이트는 16 진 검색 표임)

이 함수 는 호출자가 원하는 곳에 저장할 수 있도록 정수를 가져와 xmm08 바이트의 ASCII 문자 데이터를 반환 하는 함수입니다 xmm0. (예 : 속성 바이트를 인터리빙 한 후 또는 생성중인 문자열 등으로 비디오 메모리에)

C __m128i retval = lehex(_mm_cvtsi32_si128(x))에서 x86-64 System V 호출 규칙 또는 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"

총계 = 0x24 = 36 바이트

숫자를 16 진수로 변환하는 방법을 참조하십시오 . 작동 방식에 대한 SO. (shift / punpck의 경우 SSE2는 vpermb필요한 작업 을 저장합니다 pshufb. SSE2 / SSSE3 대신 AVX1도 movaps레지스터 복사를 피합니다 .)

공지 사항이 punpcklbw가장 낮은 소스 바이트의 최하위 니블 다음 우리에게 가장 낮은 바이트 요소의 낮은 입력 바이트의 최상위 니블을 줄 것이다 순서로 소스 피연산자와. (즉, SO의 대답에,이 bswap단지 SSE2 표준 인쇄 순서의 결과를 얻기 위해 입력을 사용하지만, 여기에 우리가 있습니다. 원하는 순서 : 각 바이트 내에서 하위 요소에서 높은 니블,하지만 여전히 작은 엔디안 바이트 순서).

더 많은 데이터 상수가 있으면 주소 지정 모드 공간을 절약하고 주소 지정 모드 mov edx, imm32를 사용하여 주소 지정 모드 공간을 절약 할 수 [rdx+16]있습니다. 또는 vpbroadcastb xmm0, [rdx+1].

그러나 16 바이트 16 진수 LUT + vpermbn>9 : n+'a'-10 : n+'0'조건을 구현하는 것보다 여전히 낫다고 생각합니다 .AVX512BW 바이트 마스킹 (마스크 vpaddb,, 머지 마스크 비교 vpaddb) 또는 AVX1 또는 SSE2 이상과 함께 3 개의 상수와 3 개 이상의 명령이 필요합니다 . ( SSE2 버전의 SO 는 숫자를 16 진수로 변환하는 방법을 참조하십시오 ). 또한 각 AVX512BW 명령어는 6 바이트 이상 (4 바이트 EVEX + opcode + modrm)이며 어드레싱 모드에서 변위가 길어집니다.

실제로 비교하기 전에 (또는 4 바이트 브로드 캐스트 메모리 피연산자가있는 EVEX) 로 높은 가비지를 지워야하기 때문에 적어도 4 개의 명령이 필요합니다 . 그리고 각각은 다른 벡터 상수가 필요합니다. AVX512에는 브로드 캐스트 메모리 피연산자가 있지만 32 비트 이상의 요소에만 적용됩니다. 예를 들어 EVEX 의 마지막 피연산자는 아닙니다 . (인텔의로드 포트는 32 비트 및 64 비트 브로드 캐스트 만로드 Uop의 일부로 무료로 수행 할 수 있으므로 인텔은 AVX512BW가이를 반영하여 바이트 또는 워드 브로드 캐스트 메모리 피연산자를 인코딩 할 수 없도록 설계했습니다. dword 방송을 수행하면 상수를 4 바이트로 압축 할 수 있습니다 : /.)andpsvpanddvpaddbxmm3/m128xmm3/m128/m8bcst

SSSE3 / AVX1 대신 AVX512VBMIvpermb 를 사용한 이유 pshufb는 두 가지입니다.

  • vpermb선택기의 높은 비트를 무시합니다. (v)pshufb제어 벡터의 높은 비트에 따라 바이트를 0으로 만들고 추가 pand또는 andps실제로 니블을 분리 해야했습니다 . XMM / 16 바이트 크기 vpermb의 경우 셔플 제어 요소의 하위 4 비트, 즉 작업 섹션[3:0] 에서 인텔 표기법의 비트 만 확인 합니다 .
  • vpermb메모리 피연산자로 셔플 할 데이터 (조회 테이블)를 취할 수 있습니다. (v)pshufbxmm / mem 피연산자는 셔플 제어 벡터입니다.

AVX512VBMI는 CannonLake / Ice Lake에서만 사용할 수 있으므로 Intel의 SDE와 같이이를 테스트하기 위해 시뮬레이터가 필요할 수 있습니다.


⭐ - 당신은 좋은 답변 스타 얻을
카밀 Kiełczewski

@ KamilKiełczewski : LOL 감사합니다. 숫자를 16 진수로 효율적으로 변환하는 것은 내가 가장 좋아하는 것 중 하나입니다. 몇 가지 깔끔한 트릭과 비트 조작을위한 훌륭한 유스 케이스입니다.
Peter Cordes

3

스칼라 , 58 40 36 바이트

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

온라인으로 사용해보십시오!

여전히 내장을 사용하여의 바이트를 반대로 Int하지만 formatInt16 진수 로 형식화하는 데 사용 합니다 . 전화 할 필요가 없습니다 toHexString.

에서 괄호를 제거했습니다 format. 이것은 이제 인수를 암시 적으로 사용하여 인수를 취할 수 있음을 의미합니다 _.


2

넷째 (gforth) , 52 51 40 바이트

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

온라인으로 사용해보십시오!

코드 설명

: 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

엑셀, 91 바이트

=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 바이트

해결책:

,/$|4_0x0\:

예 :

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

설명:

질문에서 묻는 것과 거의 동일합니다.

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

메모:

  • K4 숫자가 기본적으로 long (64 비트)이므로 -1 바이트 이므로 4 바이트 (32 비트)를 삭제

🚀 당신의 대답은 상단에
카밀 Kiełczewski

2

PHP , 31 바이트

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

온라인으로 사용해보십시오!

PHP의 packunpack 을 활용 하여 부호없는 입력을 "32 비트 little endian byte order"형식 ( V)을 이진 문자열로 압축 한 다음 "hex string, high nibble first"형식 ( H) 으로 압축을 풀고 결과를 인쇄합니다.

이것은 PHP의 내장 기능이 실제로 간단한 알고리즘을 구현하는 것보다 짧은 드문 경우 중 하나 인 것 같습니다!


PHP pack()/ unpack()함수는 대부분의 PHP 프로젝트에서 필요로하는 0 회 동안 훌륭합니다. 축하합니다, 당신은 그들의 사용을 발견했습니다!
640KB

1

, 11 바이트

⪫⮌⪪﹪%08xN²ω

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 설명:

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

파이썬 포맷에 의존하지 않고 19 바이트 :

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

온라인으로 사용해보십시오! 링크는 자세한 버전의 코드입니다. 설명:

           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

🚀 당신의 대답은 상단에
카밀 Kiełczewski


1

J , 10 바이트

8{._1{3!:3

온라인으로 사용해보십시오!

어떻게

3!:316 진 표현을위한 J "외국 연결"입니다 ( 여기 에 문서화 됨) . 즉, 16 진수로 변환하기위한 내장 기능입니다. 그러나 원하는 결과가 아닙니다. 예 : 실행 중 :

3!:3 (304767)

생산 :

e300000000000000
0400000000000000
0100000000000000
0000000000000000
7fa6040000000000

다른 줄의 의미는 위에 링크 된 문서 페이지에 설명되어 있습니다. 어쨌든, 우리는 마지막 줄의 처음 8자를 원한다는 것이 분명합니다.

_1{ 마지막 줄을 얻으십시오.

8{. 처음 8자를 가져옵니다.


🚀 당신의 대답은 상단에
카밀 Kiełczewski


1

Windows 배치, 90 바이트

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

지연된 확장을 활성화하려면 / v와 함께 명령 줄을 실행하십시오.


1

x86 32 비트 머신 코드, 24 21 바이트

changelog : -3 바이트 : @peter ferrie의 표준 add / cmp / jbe / add를 DAS 핵으로 교체

64 비트 : 여전히 24 바이트 Long 모드는 DAS opcode를 제거했습니다.
16 비트 모드 : 기본 피연산자 크기는 16 비트이지만 문제 사양은 기본적으로 32 비트입니다. 하드 코드 된 8 진수를 포함합니다.


bswap표준 순서로 수동 int-> hex로 바이트 리버스 (가장 중요한 니블 우선, 16 진수를 char 출력 버퍼에 오름차순으로 기록) 바이트 바이트에서 니블 사이의 순서를 전환하기 위해 루프를 풀 필요가 없습니다. 바이트 간.

void lehex(char buf[8] /*edi*/, uint32_t x /*esi*/);64 비트 모드에서 작동하지 않는 것을 제외하고 x86-64 System V처럼 호출 가능 합니다. (에 대한 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 테스트 케이스 ( asm 호출자 포함)는 write시스템 호출을 사용 하여 출력을 두 번 호출 한 후 버퍼에 2 개의 문자열을 추가 한 후 출력을 작성합니다. 숫자와 문자 사이의 경계에서 9와 A를 포함하여 모든 16 진수 0..F를 테스트합니다.

DAS해킹 - 86 낮은 니블의 수행을 위해, 반 캐리 플래그가 있습니다. 2 개의 2 자리 BCD 정수를 뺀 후 사용하기 위해 DAS 명령어와 같은 압축 BCD 항목에 유용합니다. AL의 낮은 니블이 0-9 범위를 벗어나면 여기에서 확실히 남용됩니다.

주목 if (old_AL > 99H) or (old_CF = 1)AL ← AL − 60H;매뉴얼의 조작 섹션 THEN 부분을 ​​확인하십시오. sbb는 항상 CF를 설정하므로 부분이 항상 발생합니다. 대문자의 ASCII 범위는 선택의 동기를 부여합니다.sub al, 0x69

  • cmp 0xD, 0xA CF를 설정하지 않습니다
  • sbb 는 DAS에 대한 입력 0xD - 0x69으로 AL = 0xA4으로 랩핑됩니다 . (그리고 CF를 설정하고 AF를 지 웁니다)
  • DAS의 첫 번째 부분에 AL-= 6 없음 (4> 9가 false이고 AF = 0이므로)
  • 두 번째 부분에서 AL-= 0x60 0x44 , 아스키 코드'D'

숫자 대 :

  • cmp 0x3, 0xA CF를 설정
  • sbb 3 - 0x69 - 1 = AL = 0x99이며 CF 및 AF를 설정합니다
  • DAS의 첫 번째 부분에 AL-= 6 없음 (9> 9는 거짓이지만 AF는 설정 됨), 0x93
  • 두 번째 부분의 AL-= 0x60이며의 ASCII 코드 인 0x33이 남습니다 '3'.

0x6aSBB에서 빼면 모든 숫자 <= 9에 대해 AF가 설정되어 모든 숫자가 동일한 논리를 따릅니다. 그리고 모든 알파벳 16 진수에 대해 지우십시오. 즉, DAS의 9 / A 분할 처리를 올바르게 활용합니다.


일반적으로 (성능을 위해) 스칼라 루프 또는 분기가없는 2x leacmp/cmov조건부 추가에 대한 조회 테이블을 사용 합니다. 그러나 2 바이트 al, imm8명령어는 코드 크기에서 큰 승리입니다.


- 64 버전 버전 : 사이에, 다른 그냥 부분 and al, 0xfstosb.

;; 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' 항상 실행하고 조건 추가는의 차이를 추가 'a'-10하고 '0'단지를 만들기 위해, if대신에 if/ else.

테스트와 같은 사용하여 작동 main으로 발신자를 내 C 응답 , 사용 char buf[8]printf("%.8s\n", buf).


예를 들어 여기 에서 온라인 작업 스 니펫을 만들 수 있습니까?
Kamil Kiełczewski

@ KamilKiełczewski : TIO는 C에서 호출자를 작성하여 asm 함수를 테스트하는 것을 불가능하게하므로 종종 귀찮게하지 않지만 sys_write고정 길이 문자열을 쉽게 요청하고 출력 할 수 있기 때문에 확실합니다 . 흥미로운 점은 TIO에서 FASM을 인식하지 못해서 NASM과 달리 32 비트 실행 파일을 만들 수 없다는 점 -felf32입니다. 어쨌든 x86-64를 선호 하며이 답변은 32 비트 코드의 바이트를 저장하지 않습니다.
Peter Cordes

⭐ - 당신은 좋은 답변 스타 얻을
카밀 Kiełczewski

1
@ JL2210 : 당신은 의미 sprintf합니까? libc에는 format-string 기반 함수 이외의 편리한 int-> string 함수가 없으며 strtoul과 같은 string-> int 만 있다고 생각하지 않습니다. 그러나 예, bswap / printf는 동적 라이브러리 (6 바이트 call [rel printf wrt ..got]호출 사이트 외에)의 함수에 대한 GOT 항목에 대한 바이트 수를 계산할 수있는 방법이 있다면 더 짧을 것입니다 . 최소한 정적으로 연결된 실행 파일은 최소한 ld일반 기본값으로 만들 때 동적보다 훨씬 작을 수 있습니다 . 그러나 정적으로 링크하는 것이 합리적이지만 코드 크기는 계산하지 않는 것이 좋습니다.
Peter Cordes

1
@ JL2210 : 이것은 xm 머신 코드 답변이며 asm 텍스트 소스 크기가 아니라는 것을 기억하십시오 . 이전 머신 코드 응답에서 libc 함수를 사용하지 않고 Linux 시스템 호출 (예 : 피보나치) 및 IDK로 비용 계산 방법 또는 머신 코드와 함께 libc 응답을 작성하려는 경우 . 부트 로더와 같이 libc를 사용할 수없는 x86 머신 코드에 대한 사용 사례가 있습니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.