Little Endian, Big Endian 에 대해 모르는 사람은 아래 포스팅을 참고하길 바란다.
나는 15살때부터 프로그래밍에 입문하였으니, 놀면서 공부한 기간 8년 + 직업적으로 다룬 기간 2년해서
나름(???) 10년인데 ENDIAN 변환은 실무에 적용하려면 버벅이게 된다...
INT 가 4 바이트고, 1 바이트는 8 비트라는 기본적인 구조는 하도 외워서 개념적으론 알고 있지만.
이렇게 낮은 단위까지 고려하며 실무에 적용 할 일이 그리 많지 않기 때문이다.
그나마 백준같은 알고리즘 문제 풀다보면 Bit 단위까지도 다루게 되지만, 이때는 비트연산, shift 연산과 관련해서 쓰지
Endian 에 관해서 다루진 않기때문에 업무에 적용하려면 머릿속이 꼬인다.
그래서, 모호한 부분에 대해서 정리하기 위해 포스팅을 작성한다.
※ 예제 코드는 C++ 로 작성하였지만, 당신이 다루는 언어가 C#이든, JAVA 든 Rust 든 상관없이 포스팅은 유효하다.
1. Endian 의 개념은 'Byte' 단위에서 사용된다.
1BYTE 에서 8,208 이라는 정수를 BIG_ENDIAN 으로 표현하면 아래와 같다.
0010 0000 0001 0000
LITTLE_ENDIAN 으로 표현하면 아래와 같다.
0001 0000 0010 0000
이를 Visual Studio Code 에서 띄워보면
[위가 빅, 아래가 리틀]
이처럼 나오는데, 8,208 이라는 숫자는 2BYTE 로 표현이 가능한 것을 알 수 있다.
여기서 ENDIAN 치환시에 서로 바뀌는 부분은
노란색과 빨간색 부분이 바뀌는 것이다.
위에서도 언급했지만 ENDIAN 에 적용되는 단위는 BYTE == 8 Bit 니까.
이를 Visual Studio 와 같은 IDE 에서는
BIG_ENDIAN == { 32, 16 }
LITTLE_ENDIAN == { 16, 32 }
와 같이 표현 해 준다.
2. 변수에 삽입할때는 Little Endian 으로 삽입 하여야 한다.
x86 프로세서의 Endian 은 LITTLE_ENDIAN 이 기준이 된다.
ARM의 경우는 BIG_ENDIAN 으로도 운용이 가능하지만,
대부분 LITTLE_ENDIAN 으로 운용되니,
그냥 DRAM 내 변수에 '할당' 된다면 LITTLE_ENDIAN 으로 넣어주면 된다.
예를 들어, 위에서 언급했던 8,208 이라는 숫자를 INT 형에 삽입하기 위해서는
BIG_ENDIAN 기준인 { 0, 0 } + { 32, 16 } = { 0, 0, 32, 16 } 이 아닌,
LITTLE_ENDIAN 기준인 { 16, 32 } + { 0, 0 } = { 16, 32, 0, 0 } 으로 삽입 해 주어야 한다
#include <iostream>
int main()
{
char BIG_ENDIAN[4] = { 0, 0, 32, 16 };
char LITTLE_ENDIAN[4] = { 16, 32, 0, 0 };
int RESULT_BIG;
int RESULT_LITTLE;
std::memcpy(&RESULT_BIG, BIG_ENDIAN, sizeof(int));
std::memcpy(&RESULT_LITTLE, LITTLE_ENDIAN, sizeof(int));
std::cout << RESULT_BIG << std::endl;
std::cout << RESULT_LITTLE << std::endl;
}
C++ 은 BYTE 단위가 없으므로 char array 형식으로 표현한다. (잘 생각해 보면 왜 char [] 인지 알 수 있다)
다른 프로그래밍 언어에서는 byte[] 로 진행하면 된다.
빅 엔디안 값으로 삽입한 변수의 값은 제대로 출력되지 않는다.
반면 리틀 엔디안 값으로 삽입한 변수의 값은 올바르게 출력된다.
즉 BIG_ENDIAN 기준으로는
{ 0000 0000, 0000 0000, 0010 0000, 0000 1000 } == { 0x00, 0x00, 0x20, 0x10 } == { 0, 0, 32 16 }
LITTLE_ENDIAN 기준으로는
{ 0000 1000, 0010 0000, 0000 0000, 0000 0000 } == { 0x10, 0x20, 0x00, 0x00 } == { 16, 32, 0 0 }
같이 표현할 수 있다.
사람이 읽을때는 '빅 엔디안' 으로 읽으면 올바르게 8,208 이 나오지만,
컴퓨터 가 읽을때는 '리틀 엔디안' 으로 읽어야 올바르게 읽힌다는 사실을
명심하자.
추가적으로
#include <iostream>
int main()
{
int test = 8208;
char byte1 = test & 0x000000ff;
char byte2 = (test & 0x0000ff00) >> 8;
char byte3 = (test & 0x00ff0000) >> 16;
char byte4 = (test & 0xff000000) >> 24;
}
위 코드를 통해서 8208 이라는 INT 형 변수를 BYTE 단위로 뽑아볼 수 있는데,
뽑아 보면 우리가 아까 배웠던
LITTLE_ENDIAN 순서인 { 16, 32, 0, 0 } 로 저장되어 있다.
3. 네트워크를 통해 넘어온 값을 바로 출력할 때는 ENDIAN 변환이 필요 없다.
위에서는 변수에 값을 '할당' 한 뒤에 출력 할려다 보니 LITTLE_ENDIAN 으로 처리했지만,
만약 네트워크를 통해 넘어오는 값을 직접 PRINT 찍어서 확인하려면
ENDIAN 변환이 필요 없다, 일반적으로 네트워크를 통해 전송되는 형식은 BIG_ENDIAN 이기 때문이다.
※ 물론 자체적으로 사용되는 내부망에서 LITTLE_ENDIAN 을 사용하고자 한다면, 상관없다.
CLASS 구조를 토대로한 데이터를 주고받을 때 굳이 BIG_ENDIAN 을 쓴다면
불필요한 배열 REVERSE 과정이 추가되기 때문이다.
어디까지나 변수에 값을 할당할 때 LITTLE_ENDIAN 이 필요 하다는 것을 상기하길 바란다.
'Programming' 카테고리의 다른 글
COM 개체와 Thread 안정성 (0) | 2023.04.30 |
---|---|
코딩 네이밍 규칙 (0) | 2021.07.22 |