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


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 그래서 음수 대 비트 패턴 &15온 int단지 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 + vpermb가 n>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하지만 format을 Int16 진수 로 형식화하는 데 사용 합니다 . 전화 할 필요가 없습니다 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의 pack 과 unpack 을 활용 하여 부호없는 입력을 "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 lea및 cmp/cmov조건부 추가에 대한 조회 테이블을 사용 합니다. 그러나 2 바이트 al, imm8명령어는 코드 크기에서 큰 승리입니다.


- 64 버전 버전 : 사이에, 다른 그냥 부분 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' 항상 실행하고 조건 추가는의 차이를 추가 '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.