티스토리 뷰

Coding/C

little endian과 big endian

빠리빵 2018. 5. 22. 13:32
 
#include

/*
Little, Big endian
데이터가 실제 메모리에는 어떻게 저장될까?
*/

void main(void) {
	int a = 0x01234567;	
	/*
	a는 스택영역에 저장될 것이다.
	int형은 4byte이기 때문에 (주소는 편의상 0x1000 이라고 가정한다.)
	
	주소 - 데이터
	1000 - 0x?? (1byte)
	1001 - 0x?? (1byte)
	1002 - 0x?? (1byte)
	1003 - 0x?? (1byte)

	위와 같이 저장될 것이다.
	참고로 1byte는 8bit이다. 따라서 16진수로 2개(?)를 저장할 수 있다.
	0xE3 이렇게.. 4bit는 0~15(F)를 표현할 수 있기 때문에
	아무튼 어떻게 저장되는지 출력을 해보자.
	char type은 1byte이기 때문에 이 점을 활용할 수 있겠다.
	.2는 2자리까지 출력, 0x1 말고 0x01로 보이도록..
	*/

	printf("%#.2x\n", (char)*(&a));
	/*
	우선 16진수라는 것을 편하게 확인할 수 있도록 #을 앞에 추가했다. (0x를 붙여서 출력)
	&a -> a의 주소
	*(&a) -> a의 주소에 있는 data -> 0x1234567
	(char)*(&a) -> char형으로 형변환을 함으로써 1byte만 출력한다.
	*/
	printf("%#.2x\n", *((char *)(&a)));	// 이런 식으로도 출력할 수 있겠다.
	// 결과는 0x67

	// 주소와 데이터를 같이 출력해보자.
	printf("address : %#.2x data : %#.2x\n", (char *)(&a), (char)*(&a));
	printf("address : %#.2x data : %#.2x\n", (char *)(&a+1), (char)*(&a+1));
	printf("address : %#.2x data : %#.2x\n", (char *)(&a+2), (char)*(&a+2));
	printf("address : %#.2x data : %#.2x\n", (char *)(&a+3), (char)*(&a+3));
	/*
	위와 같이 출력하면 생각대로 되지 않는다. 
	a가 int type이기 때문에 주소의 + 연산에서 4byte씩 증가된다.
	( ) 연산자의 우선순위가 높기 때문에 (&a+1)가 실행 후 (char *) 형변환이 진행된다.
	이미 (&a+1)에서 4byte를 증가시켜버렸기 때문에 이상하게 나올 수 밖에..
	포인터를 사용하는 경우에 항상 data의 type과 연산자 우선순위 신경쓰자.
	
	참고로 (char *)&a + 2 이런 식으로 괄호를 없앴으면 제대로 출력된다.
	대충 배운 지식의 활용은 오류를 발생시킨다..
	*/

	printf("\naddress : %#.2x data : %#.2x\n", (char *)(&a),    (char)*(&a)			);
	printf("address : %#.2x data : %#.2x\n",   (&(char)a) + 1,  *((&(char)a) + 1)	);
	printf("address : %#.2x data : %#.2x\n",   &(char)a + 2,    *(&(char)a + 2)		);
	printf("address : %#.2x data : %#.2x\n",   ((char*)&a + 3), *((char*)&a + 3)	);
	/*
	위에서 다양하게 출력하는 형태를 자주 보고 익숙해지자.. ( )연산의 우선순위와 주소연산 등을 생각할 것

	결과는
	주소 - 데이터
	1000 - 0x67 (1byte)
	1001 - 0x45 (1byte)
	1002 - 0x23 (1byte)
	1003 - 0x01 (1byte)

	오 1000 주소에 0x01부터 저장될 줄 알았더니 아니다. 67 45 23 01 순서대로 저장된다.
	이유는 little endian 형식으로 저장되기 때문
	우선 구글링을 하다보면 주소의 증감이 뒤죽박죽이라 외우기가 힘들다.. 누구는 아래로 내려가면 주소를 작게 그려놓고..
	외우는 쉬운 방법은 little endian은 '낮은' 주소에는 '작은' 값이 저장된다! 라고 생각하면 편하겠다.
	예로 1000 주소(낮은 주소)에는 0x01234567 중에서 0x67(작은 값, 16진수에서는 뒤쪽 값이 끼치는 영향이 작다.)이 저장된다.
	big endian은 반대로 '높은' 주소에는 '작은' 값이 저장된다라고 생각하면 되겠다.

	왜 이런 식으로 만들었을까?
	빅엔디안의 경우 사용자가 디버깅이 쉬워진다고 생각하면 되겠다. 사람이 생각하는대로 저장되기 때문에.
	리틀엔디안의 경우 하위 비트를 얻기 쉽다고 한다.
	예로 0x3B라는 값은 0x0000003B 이며, 메모리의 낮은 주소부터 3B 00 00 00 값이 저장된다.
	빅엔디안이었더라면 3B(하위비트)를 얻기 위해서 주소의 값을 3 더해야한다.
	사실 하위 비트를 쉽게 얻는 것이 자세히 어떤 장점이 있는지는 모르겠다.
	더 찾아보니 가산기가 덧셈연산을 하는 과정에서 올림이 발생하기 때문에 하위 비트부터 더하는 것이 좋다.
	이러한 과정에서 가산기의 설계가 더 단순해졌다하니.. 과거에서는 이 구조가 더 효율적이었나보다.
	시간이 되면 더 찾아보는 것으로 하고.. 요즘 우리가 쓰는 것들은 대부분 little endian 방식이라 생각하면 되겠다.
	*/

	system("pause");
}


'Coding > C' 카테고리의 다른 글

배열을 함수의 인자로 넘기는 경우 주의할 점  (0) 2018.05.22
1차원 배열의 포인터  (0) 2018.05.22
포인터의 연산  (0) 2018.05.22
pointer 와 선치, 후치 연산자  (0) 2018.05.20
static 및 extern // case03  (0) 2018.05.20
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함