ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • BitConverter.ToIntXX() 함수 구현해보기
    개발/C++ 2019. 11. 6. 02:35

    C#은 C++과 Java의 장점을 두루 갖고 있다. 비교적 늦게 태어난 언어인 만큼 단점보다는 장점이 더 많아 보인다. 네트워크 라이브러리 쓰기도 편하고 스레드도 지원을 잘한다. Java는 손을 뗀 지 조금 돼서 잘 모르겠는데, C#에는 여러 종류의 변환 함수를 지원한다. 문자열 변수를 바이트로 변환해준다든가(Encoding.UTF8.GetBytes(Name)), char형 배열에서 오프셋을 지정해 원하는 바이트만큼 읽어온다든가. 후자의 기능을 갖고 있는 함수가 BitConverter.ToIntXX() 계열의 함수다. 사실은 이 함수를 똑같이 구현하는 게 목적이 아니라 내부적으로 어떤 원리를 갖고 있는지 알아보려고 한다.

     

    설명하려고 하는 함수는 가변 버퍼에서에서 발견할 수 있다. 서버 프로그래밍에서 가변 버퍼는 버퍼에 넣고자 하는 값을 복수로 넣고, 받는 쪽에서 사용할 때 넣은 순서대로 데이터에 접근하는 방식으로 사용된다. int, char, short 순서로 넣었다면 꺼낼 때도 int, char, short 순서로 꺼내야 한다는 이야기. 이 함수를 들여다 보면서 C#의 BitConverter.ToIntXX() 계열의 함수가 떠오른 건 우연이 아니다. 개발을 한층 쉽게 만들어준다고 느껴 꽤 기억에 남았나 보다.

     

    핵심은 시프트 연산이다. char형 배열로 동적할당된 buf라는 버퍼가 있다. 이 버퍼에 short형 변수를 쉽게 넣기 위해 시프트 연산을 이용해보자. SetShort(short num) 함수는 short 형 변수 하나만을 인자로 받는다. 기본적인 동작 방식은 인자의 크기에 따라 각 바이트에 값을 나눠 넣는 것이다.

     

    short 타입은 크기가 2바이트이기 때문에 말 그대로 두 단위 바이트에 숫자의 크기에 따라 적절하게 값을 분리해야 한다. 이미 어느 정도 답이 나왔다. 1바이트의 표현 범위는 unsigned 기준으로 0~255이다. 2바이트의 표현 범위는 65535까지인데 이 숫자는 256^0 * 255 + 256^1 * 255에서 나온 값이다.

     

    이진수는 자릿수가 2의 배수로 올라가고 바이트는 256의 배수로 올라간다. 바이트는 256진수인 것이다. 이 원리를 통해서 300이라는 숫자를 바이트 단위로 분해해보자. 답은 하위 바이트에 44가, 그다음 상위바이트에는 1이 들어간다. 300은 256^0 * 44 + 256^1 * 1이기 때문이다. 코드로 살펴보자.

    1
    2
    3
    4
    5
    6
    void Buffer::SetShort(short num)
    {
        *curruent++ = num;
        *curruent++ = num >> 8;
        buf_size_ += 2;
    }

    current 변수는 동적할당으로 만든 buf의 시작 포인터를 할당받아 버퍼에 값이 세팅될 때마다 해당 크기만큼 주소의 위치를 이동하는 이동하는 역할을 맡았다. 하위/상위 바이트를 언급했던 이유는 *current에 num을 대입할 때 일어나는 일 때문이다. 2바이트인 num을 1바이트 변수에 대입하면 상위 바이트가 짤린다. 즉 300을 대입하면 44만 들어간다는 이야기.

     

    두 번째 줄인 *current++ = num >> 8이 설명의 핵심으로, 시프트 연산으로 오른쪽으로 8비트를 이동한다는 것은 1바이트 단위로 시프트 연산을 수행한다는 의미다. 300을 256진수로 표현하면 1 44(오른쪽이 하위바이트)이므로 300 >> 8 연산의 결과는 1이 된다. 나중에 GetShort() 할 때 시프트 연산을 한 번 더 사용해 원래의 값을 계산해주면 된다. 다음이 GetShort 함수. current[0]에 44, current[1]에는 1이 들어있는데 1 << 8을 하면 256이 된다. 44 + 256 = 300.

    1
    2
    3
    4
    5
    6
    void Buffer::GetShort(OUT short& num)
    {
        num = static_cast<unsigned char>(current_[0]) + ((static_cast<unsigned char>(current_[1])) << 8);
        current_  += 2;
        buf_size_ += 2;
    }

    댓글

Designed by Tistory.