How do I convert a string representing a signed hex int into its signed int Doubleword number in 80x86?

后端 未结 2 623
日久生厌
日久生厌 2021-01-28 02:46

So I am taking an assembly language course and I am stuck on this problem from the book: Using the windows 32 console (so I have an io.h to use), I am supposed to t

相关标签:
2条回答
  • 2021-01-28 02:54

    If you need to convert a character (for simplicity, say, in upper case) representing a hex digit into the value of that digit you need to do this:

    IF char >= 'A'
      value = char - 'A' + 10
    ELSE
      value = char - '0'
    ENDIF
    

    If you need to do the reverse, you do the reverse:

    IF value >= 10
      char = value - 10 + 'A'
    ELSE
      char = value + '0'
    ENDIF
    

    Here you exploit the fact that the ASCII characters 0 through 9 have consecutive ASCII codes and so do the ASCII characters A through F.

    0 讨论(0)
  • 2021-01-28 03:05

    There are some bugs in your code.

    First, in 0 ... 9 string to integer conversion code, you don't do ASCII to binary conversion as you should do, but instead you do and ebx,0Fh, which is incorrect. You need to subtract '0' (30h) from each ASCII character, like this:

    mov bl,[esi]
    sub bl,'0' ; sub bl,30h
    

    Then, also in 0 ... 9 string to integer conversion code:

    and    eax, ebx
    

    If the number consists of only 0...9 digits, and eax, ebx will produce always 0. It should be:

    or al,bl
    

    Then, you do shl eax,4, even if you don't know if there will be more digits. That means that the number will be 16 times bigger than it should.

    Then, you give the example input with spaces, but your code does not handle spaces (20h) properly, it ends reading input for any value below '0' (30h), it seems to accept only leading spaces (skip this if you don't want to accept spaces in between).

    So, the entire code block above should be:

    WhileDigitD:
            cmp    byte ptr [esi], ' ' ; delete this if you don't want spaces in between.
            je     next_char           ; delete this if you don't want spaces in between.
            cmp    BYTE PTR [esi],'0'  ; compare next character to '0'
            jb     EndWhileDigitD      ; not a digit if smaller than '0'
            cmp    BYTE PTR [esi],'9'  ; compare to '9'
            ja     TestForHexD      
            mov    bl,[esi]            ; ASCII character to BL
    
            sub    bl,'0'              ; sub bl,30h -> convert ASCII to binary.
    
    shift_eax_by_4_and_add_bl:
            shl    eax,4               ; shift the current value 4 bits to left.
            or     al,bl               ; add the value of the current digit.
    
    next_char:
            inc    esi
            jmp    WhileDigitD
    

    I also added labels next_char and shift_eax_by_4_and_add_bl. The reason for next_char should be evident, shift_eax_by_4_and_add_bl is to minimize duplicate code of 0...9 and A...F code blocks, see below.

    You don't check that that the hexadecimal A...F digit is within range A ... F, only that it's below or equal to F. Otherwise it has same bug with shl eax,4. And as usually duplicate code should be avoided, I added shift_eax_by_4_and_add_bl label to minimize duplicate code.

    So I think it should be:

    Edit: corrected sub bl,31h -> sub bl,('A'-0Ah).

    TestForHexD:
            cmp    BYTE PTR [esi], 'A'
            jb     EndWhileDigitD
            cmp    BYTE PTR [esi], 'F'
            ja     EndWhileDigitD
            mov    bl,[esi]
            sub    bl,('A'-0Ah)         ; sub bl,55 -> convert ASCII to binary.
            jmp    shift_eax_by_4_and_add_bl
    
    0 讨论(0)
提交回复
热议问题