숫자를 문자열로 변환하는 방법

  • 작성자
    조재혁(Mminzkn@minzkn.com)

  • 고친과정
    2005년 4월 23일 : 처음씀
    2006년 6월 18일 : 설명추가

개요

어셈블리(Assembly) 프로그래밍을 하다가 보면 Register 또는 Memory에 저장된 어떤 결과값을 화면에 표시해야 할 필요가 있습니다. 이때 저장된 결과값을 각 진법에 맞는 자릿수 단위로 문자화하는 변환이 필요하게됩니다.

즉, 1234라는 10진수의 결과값이 저장되어 있을때 화면에 10진수로 출력하기 위해서는 1, 2, 3, 4로 자릿수로 분리하고 화면에 출력하기 위한 Ascii값으로 변환하는 과정이 필요합니다.

이때 숫자 0은 Ascii 16진수값으로 30H에 해당하고 1은 31H, ... 9는 39H가 됩니다. 즉, 분리된 1, 2, 3, 4를 화면에 출력하려면 31H, 32H, 33H, 34H 로 출력을 해야 한다는 의미입니다.

이론

각 자릿수를 분리하려면 어떻게 하면 될까요? 어떠한 값 x가 있을때 이것을 z진법으로 자릿수를 분리하려면 y = x % z 와 같이 나머지를 취하여 가장 낮은 자릿수를 구할수 있고 다음자릿수를 구하기 위해서 x = x / z(실수나눗셈이 아니고 정수나눗셈으로 소숫점은 버린다)으로 방금 구했던 가장 낮은 자릿수를 떨궈버릴수 있습니다. 이와 같은 방법을 반복하여 x가 0이 될때까지 반복하면 각 자릿수가 하나씩 뽑아져 나오게 되는것입니다.

조금 응용하여 예를 들어보겠습니다. 만약 10진수로 5라는 숫자가 있는데 이것을 2진법으로 자릿수를 분리하려면 어떻게 할까요? 먼저 y = 1 = 5 % 2입니다. 이것이 가장 낮은 자릿수가 되고 x = 2 = 5 / 2가 다음 계산할 값이 됩니다. 이제 다시 y = 0 = 2 % 2 와 같이 밑에서 두번째 자릿수가 됩니다. 다시 x = 1 = 2 / 2이 되고 y = 1 = 1 % 2와 같이 밑에서 세번째 자릿수가 됩니다. 다시 x = 0 = 1 / 2가 되어 0이 되므로 끝이 납니다. 결국 1, 0, 1로 자릿수가 분리되며 이를 Ascii로 각 자릿수를 변환하면 31H, 30H, 31H가 됩니다.

이것을 C언어로 표현하면 간단히 다음과 같은 짧은 함수가 작성될수 있을겁니다.
char * int_to_string(unsigned int s_value /* 변환하고자 하는 값을 입력받는다 */, int s_radix /* 원하는 진법수 입력받는다 */)
{
    /* 배열을 활용하여 0번째 인덱스는 30H가 되는 식으로 자릿수를 Ascii로 변환하는 테이블을 선언한다. */
    static const char c_base_ascii[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 'A', 'B', 'C', 'D', 'E', 'F'};
    /* C언어에서 문자열을 반환하기 위해서 static 메모리 공간이 필요하다. 하지만 Thread상황에서 사용할것이라면 malloc으로 할당하여 반환해야 한다. 여기서는 단지 예제를 보이기 위해 간단하게 static을 잡았을뿐이다. 아래에서 buffer를 어떻게 반환하는지 각자 유심히 보기를 바란다 */
    static char s_buffer[ 64 ] = {0, };
    /* buffer의 끝을 가르키는것으로 offset을 시작한다. */
    size_t s_offset = sizeof(s_buffer) - 1;

    do {
        s_buffer[--s_offset] = c_base_ascii[ s_value % s_radix /* y = x % z */ ];
        s_value /= s_radix; /* x = x / z */
    }while(s_value != 0u); /* 값이 0이 될때까지 반복 */

    return((char *)(&s_buffer[s_offset]));
}


예제

  • C언어 예제
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char * int_to_string(unsigned int s_value, int s_radix)
    {
        static const char c_base_ascii[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        static char s_buffer[ 64 ] = {0, };
        size_t s_offset = sizeof(s_buffer) - 1;
    
        do {
            s_buffer[--s_offset] = c_base_ascii[ s_value % s_radix ];
            s_value /= s_radix;
        }while(s_value != 0u);
    
        return((char *)(&s_buffer[s_offset]));
    }
    
    void test(unsigned int s_value)
    {
        char s_base2[64];
        char s_base8[64];
        char s_base10[64];
        char s_base16[64];
    
        (void)strcpy((char *)(&s_base2[0]), (const char *)int_to_string(s_value, 2));
        (void)strcpy((char *)(&s_base8[0]), (const char *)int_to_string(s_value, 8));
        (void)strcpy((char *)(&s_base10[0]), (const char *)int_to_string(s_value, 10));
        (void)strcpy((char *)(&s_base16[0]), (const char *)int_to_string(s_value, 16));
    
        (void)fprintf(stdout, "%d = \"%sb/%so/%sd/%sh\"\n",
            s_value,
            (char *)(&s_base2[0]),
            (char *)(&s_base8[0]),
            (char *)(&s_base10[0]),
            (char *)(&s_base16[0]));
    }
    
    int main(void)
    {
        test(12345678);
    
        return(EXIT_SUCCESS);
    }
    


  • 어셈블리 예제 (MASM)
    ; 이 함수는 AX값을 문자열로 출력하고 초기 BX값을 바꾸면 그에 해당하는 진수표기법으로 바뀌게 됩니다.
    P_PRINT_BIN     PROC NEAR ; void near pascal P_PRINT_BIN(AX)
                    MOV BX, 16 ; 16진수 출력 (여기를 바꾸면 진수표기법이 바뀜 2는 2진법, 4는 4진법, 8은 8진법, ...)
                    XOR CX, CX
    L_PRINT_BIN_0:
                    XOR DX, DX
                    DIV BX
                    CMP DX, 10
                    JL L_PRINT_BIN_LESS_0
                    SUB DX, 10
                    ADD DX, 'A'
                    JMP L_PRINT_BIN_LESS_1
    L_PRINT_BIN_LESS_0:
                    ADD DX, '0'
    L_PRINT_BIN_LESS_1:
                    PUSH DX
                    INC CX
                    OR AX, AX
                    JNZ L_PRINT_BIN_0
    
    ;                PUSH CX
    ;                MOV AX, CX
    ;                MOV CX, 8
    ;                SUB CX, AX
    ;L_PRINT_BIN_ZERO_0:
    ;                JCXZ L_PRINT_BIN_ZERO_1
    ;                DEC CX
    ;                MOV AH, 02H
    ;                MOV DL, '0'
    ;                INT 21H 
    ;                JMP SHORT L_PRINT_BIN_ZERO_0
    ;L_PRINT_BIN_ZERO_1:
    ;                POP CX
    
    
    L_PRINT_BIN_1:
                    POP DX
                    MOV AH, 02H
                    INT 21H
                    LOOP L_PRINT_BIN_1
                    RETN
    P_PRINT_BIN     ENDP
    



/*
[ FrontPage | PrintView | RawView | RSS ]

Copyright ⓒ MINZKN.COM
All Rights Reserved.

MINZKN
*/