참고 자료 :
http://teaching.idallen.com/cst8281/10w/notes/110_byte_order_endian.html
http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/endian.html
http://stackoverflow.com/questions/1568057/ascii-strings-and-endianness
http://stackoverflow.com/questions/5804824/is-it-true-that-endianness-only-affects-the-memory-layout-of-numbers-but-not-str
-----
리틀엔디안 방식에서는 낮은 위치의 데이터(Least Significant Byte)가 낮은 주소에 들어간다.
#include <stdio.h>
int main(void)
{
int num = 0x01020304;
char * ptr = (char*)#
printf("%p %p %p %p\n", ptr, ptr + 1, ptr + 2, ptr + 3);
printf("%8d %8d %8d %8d\n", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
puts("");
}
그렇다면 문자열의 경우에는 어떨까?
#include <stdio.h>
int main(void)
{
char * str = "abcd";
printf("%p %p %p %p\n", str, str + 1, str + 2, str + 3);
printf("%8c %8c %8c %8c\n", *str, *(str + 1), *(str + 2), *(str + 3));
puts("");
}
int형 데이터를 가지고 테스트 했을 때와 반대의 결과가 나왔다.
글의 맨 처음에서 "리틀 엔디안에서는 낮은 위치의 데이터(LSB)가 낮은 주소에 들어간다" 고 하지 않았는가?
그렇다면 character string의 경우에도 00225858번지부터 d, c, b, a 이렇게 데이터가 들어가는게 맞지 않을까?
정답은 그렇지 않다 이다.
----------
endianness 문제, 즉 데이터의 저장 순서를 고려해야 하는 문제는 메모리의 저장 단위보다 큰 데이터를 메모리에
저장해야 할 때 발생하게 된다.
우리가 사용하는 컴퓨터 메모리에서는 일반적으로 주소 번지마다 1byte의 저장 공간을 가진다.
여기서 만약 4byte 크기의 int형 데이터를 메모리에 저장하기 위해서는, 4byte크기의 int형 데이터가 먼저 1byte단위
로 쪼개져서 메모리에 저장되어야 한다. 그런데, 이 때 int형 데이터를 메모리에 저장하는 두 가지 방법이 생기게 된다.
1. Least Significant Byte를 낮은 주소에 저장하는 방식 (리틀엔디안)
2. Least Significant Byte를 높은 주소에 저장하는 방식 (빅엔디안)
즉, 메모리에 배치될 때의 데이터의 순서를 고려해야 하는 상황이 발생한 것이다.
여기서 endianness 문제가 발생한 것은 애초에 메모리의 저장 단위인 1byte보다 큰 데이터인 4byte를 저장하려 했기
때문이라는 것을 조심하자.
앞의 예에서는 메모리의 저장 단위가 1byte인데 여기에 4byte의 int형 데이터를 저장하려고 했으니 endianness 문
제가 발생하게 되고, 따라서 리틀엔디안이니 빅엔디안이니 라는 얘기들이 오가게 된다.
반면 character의 경우에는 C언어에서는 character의 크기가 1byte인 ASCII 표현방식을 사용하므로 endianness
문제가 발생하지 않는다. (ASCII character의 경우)
그리고 character string은 단순히 character들의 array이기 때문에 character string 또한 endianness 문제가 발생
하지 않는다. (ASCII string의 경우)
따라서 만약 character string을 메모리에 저장한다면 하드웨어가 어떠한 엔디안 방식을 사용하던지간에 항상
string의 첫번째 character가 낮은 주소에 저장된다. "abcd"라는 문자열이 있으면, a가 낮은 주소에 저장되는 것이다.
한 가지 주의할 점은 이는 어디까지나 C의 char가 1byte의 ASCII character를 사용하기 때문이라는 것이다.
만약 메모리에 저장해야할 character data가 유니코드와 같이 multi-byte character라면 얘기가 또 달라진다.
유니코드의 경우에는 2byte의 크기를 가지므로 1byte의 저장공간 단위를 사용하는 메모리에 저장되기 위해서는
2byte 데이터가 1byte단위로 쪼개져야 하고, 따라서 이 때는 endianness 문제가 발생하게 된다.
(unicode character의 경우)
-----
참고1)
int형 데이터에서 bitwise 혹은 bitshift 연산을 수행할 때는 endianness문제를 고려하지 않아도 된다. 하드웨어에서
알아서 바이트들을 잘 arrange 해주기 때문이다. int형 데이터 0x01020304가 리틀엔디안 방식에서 낮은 주소 순으로
0x04, 0x03, 0x02, 0x01 이렇게 배치되지만 int값을 출력할 때는 0x01020304라고 올바르게 출력되는거랑 비슷하다고
생각하면 되지 않을까.
참고2)
32bit 레지스터에 32bit 데이터가 저장되는 상황에서는 리틀엔디안 방식이니 빅엔디안 방식이니 하는 얘기들을 할 필
요가 없다. 레지스터는 단순히 자기가 저장할 수 있는 32bit 공간에 32bit 데이터를 저장할 뿐이고, 가장 오른쪽 비트는
least significant bit가 되고, 가장 왼쪽 비트는 most significant bit가 된다. 그저 이 뿐이다.
32bit 공간에 32bit 데이터를 저장하는데 있어 레지스터 내의 바이트들을 무언가 다른 방식으로 재배치 할 이유가 없다.
endianness 문제는 multi-byte quantity를 쪼개서 메모리 공간 안에 연속적으로 배치해야 될 때 발생한다는 것을 다시
기억하자.
참고3)
int형 값을 저장하는 첫 예제에서 ptr변수에 저장되는 num 데이터의 주소 값은 첫 예제에서와 마찬가지로 낮은 위치의
데이터가 낮은 주소에 저장된다.
그림에서 ptr 변수의 주소는 0x001cfc44인데, 이 주소가 가진 값을 보면 num 변수의 주소가 반대로 저장되어 있음을
알 수 있다. 즉, 0x01020304값은 num에 저장될 때 반대 방향으로 저장되고, 이 값의 주소(num 주소) 역시 ptr변수에
저장될 때 반대 방향으로 저장됨을 알 수 있다.
마찬가지로, char string값을 저장하는 두 번째 예제에서도 str변수에 저장되는 문자열의 주소 값은 낮은 위치의 데
이터가 낮은 주소에 저장된다.
그림에서 str 변수의 주소는 0x002df9a8인데, 이 주소가 가진 값을 보면 문자열의 주소가 반대로 저장되어 있음을 알
수 있다. 즉, 문자열 자체는 메모리에 정방향으로 저장되고, 문자열을 가리키는 주소값 자체는 str 변수에 저장될 때
반대 방향으로 저장됨을 알 수 있다.
'C > 공개글' 카테고리의 다른 글
c는 call-by-value? call-by-reference? (0) | 2014.11.12 |
---|---|
비주얼스튜디오에서 삼중 문자 기능 사용하기 (0) | 2014.10.15 |
MinGW에서 pthread 사용하기 + 주의사항 (0) | 2014.09.19 |
fgetc 함수의 리턴 값은 왜 int형인가 (fgetc(), getc() and getchar()) (0) | 2013.07.16 |
signed와 unsigned로 명시하는 것의 차이? (0) | 2013.07.16 |