메모리 하나당 차지하는 바이트 수에 대해 궁금한 점이 있습니다.

alfhd00의 이미지

제가 알기로는 메모리 하나당 8bit 즉, 1byte로 알고 있습니다.

그런데 배열을 배우면서 조금 의문이 드는 것이 있습니다.

제가 첨부한 그림처럼 크기가 2인 배열을 선언했습니다.

그리고 그것의 주소를 출력했죠.

배열의 type이 int형이기 때문에 4byte를 차지하므로 인덱스끼리의 차가 4가 됩니다.

여기까지는 저도 이해가 됩니다.

그리고 저 값은 int형으로 잡혀있는 메모리 중 가장 첫 번째 메모리 주소가 출력된 것입니다.

메모리 하나의 주소인데..;

16진수로 8자리입니다. 16진수는 2자리씩 4bit를 가집니다.

총 32bit=4byte라는 얘기인데......메모리 하나당 왜 8bit가 아닙니까?

그리고 만일 메모리 하나당 4byte면 int형 선언했을 때 메모리 하나만 가지면 되는 거 아닌가요?

+32bit 체제에서 32bit=4byte가 연산 단위라면 int x; 이렇게 선언했을 때 메모리 하나 할당받아야 하는 거 아닌가요?

File attachments: 
첨부파일 크기
Image icon 없음.png7.04 KB
HDNua의 이미지

1. 무슨 말씀을 하시는지 잘 모르겠어서, 위 상황을 설명하는 그림을 그렸습니다.
이걸 보고도 이해가 안 되신다면 달리 드릴 말씀이 없을 것 같네요.

댓글 첨부 파일: 
첨부파일 크기
Image icon image001.png78.14 KB
Image icon image002.png128.42 KB

저는 이렇게 생각했습니다.

jick의 이미지

(이렇게 말하면 꼭 무슨 성문종합영어 공부하는 것 같지만... -.-)

메모리는 하나씩 셀 수 있는 대상이 아니므로 "메모리 하나"라는 말은 없습니다. 이건 "휘발유 하나"나 "옷감 하나"와 마찬가지지요.

휘발류 1리터 혹은 옷감 한 필이라고 해야 얼만큼의 양을 말하는지 알 수 있습니다.

그러므로 메모리 1바이트는 8비트이고 (일반적인 32비트 머신에서) int형 하나는 4바이트 즉 32비트입니다.

* 그리고 (잘 생각해 보면 당연한 말인데) "메모리의 주소"는 "해당 주소에 들어있는 값"과 다릅니다. 두 개를 혼동하시는 듯.

익명 사용자의 이미지

다시 질문을 읽어보니, 컴퓨터 아키텍쳐에 대한 이해가 더 필요하실듯합니다.

암기식의 답변을 원하지 않으시지요?
저도 그렇습니다.
"메모리 하나"라고 말하시는건 다음과 같습니다. (이해가 잘 되실지 모르겠지만)
예를들어,
0x10000000 을 Read하면 4byte의 값이 나옵니다. (ex. 0x12345678)
그리고,
0x10000004 를 접근합니다. 그럼 또 4byte의 값이 나옵니다.
이때,
여기서 "메모리 하나"의 의미를 보자면
0x10000000 - 1byte (ex. 0x78 : 0b 01111000)
0x10000001 - 1byte (ex. 0x56 : 0b 01010110)
0x10000002 - 1byte (ex. 0x34 : 0b 00110100)
0x10000003 - 1byte (ex. 0x12 : 0b 00010010)
이렇게 보는것이 맞습니다. 맞지요?

왜 하나의 addressing이 1byte의 값을 가져오냐는 질문으로 돌아가면, 지금 제가 가지고 있는 의문과 같게 되는데..
맞나요?

이 질문이 맞다면, 1byte는 아키텍쳐 역사로 봤을 때, 7bit = 1byte 인 시스템도 있었고, 9bit이 1byte인 시스템도 있었습니다.
꼭 8bit이 1byte라고 정해졌던 적은 없었다고 합니다.
byte라는 것이 bite(한입 베어물다)에서 유래된 용어입니다. 플랫폼에서 한번에 처리하는 데이터 크기를 의미하는 것입니다.

그렇다면 왜 1Byte가 7bit 이나 8bit 이나 9bit 혹은 왜 16bit이 아니고 32bit이 아닌가? 라고 한다면,
답은 컴퓨터 아키텍쳐가 영문권인 곳에서 발전했기 때문이라고 합니다.
결국 0101010 로 이루어진 전자신호를 사람이 인식할 수 있는 문자로 저장을 했어야 했는데,
이런 문자를 표현하는 코드들의 숫자가 7bit ~8bit 으로 충분했기 때문이라고 합니다.
(ASCII : 제어문자(32개), 출력가능문자(영소문자, 영대문자, 숫자, 기타 기호, parity bit 등등)
현재도 ASCII extended 부호를 사용하고 있습니다. (7bit + 1bit)
이래서 1Byte에 문자 1개를 저장할 수 있는 8bit 구조가 된 것이라고 합니다.

한반도를 기반으로 컴퓨터아키텍쳐가 발전했다면 1byte가 16bit이 되었을거라는 유머도 있더라구요.

ps 1. 32bit 프로세서 64bit 프로세서 에서 말하는 bit는 Addressing size와 관련된 것이기 때문에 1byte 단위와는 무관 한 것 같습니다.
ps 2. 여기서 메인메모리와 캐시정책에 따라 실제 메인메모리에서 읽어오는 data양은 다를 수 있습니다.

제이디의 이미지

드디어 가입ㅎㅎ

shint의 이미지

1 BYTE == 8 Bit == 11111111 (Bin) == 0xFF (Hex) 입니다.

unsigned char == 0 ~ 255 == 0x00 ~ 0xFF
signed char == -128 ~ 127 == 0x10000000 ~ 0x01111111
http://feelpass.tistory.com/324

0xF 는 1111 이고 4 Bit 입니다.
0x0 은 0000 이고 4 Bit 입니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

제이디의 이미지

뭐가 잘못됬나요?? 뭘 말씀하시고 싶으신건지...

shint의 이미지

#include <iostream>
 
 
int main(int argc, char** argv)
{
 
{
	int a = 10;
	int b = (int)&a;	printf("int b = (int)&a;         b:%x\n", b);
	b = (int)b+1;		printf("b = (int)b+1;            b:%x\n", b);
	int * c = (int*)b;	printf("int * c = (int*)b;       c:%x\n", c);
	*c = 11;			printf("*c = 11;                 c:%x\n", c);
	*c = 12;			printf("*c = 12;                 c:%x\n", c);
						printf("\n");
}
 
{
	int a = 10;
	int b = (int)&a;		printf("int b = (int)&a;       b  :%x\n", b);		//4
	b = (int)b+1;			printf("b = (int)b+1;          b  :%x\n", b);		//5
	int * c = (int*)b;		printf("int * c = (int*)b;   c+1:%x\n", c+1);	//6
	*c = 11;				printf("*c = 11;               c+2:%x\n", c+2);	//7
	*c = 12;				printf("*c = 12;               c  :%x\n", c);		//5
	c = (int*)b+1;			printf("c = (int*)b+1;         c  :%x\n", c);		//5
							printf("\n");
}
 
{
	int a = 10;
	int b = (int)&a;		printf("int b = (int)&a;       b  :%x\n", b);		//4
	b = (int)b+1;			printf("b = (int)b+1;          b  :%x\n", b);		//5
	char * c = (char*)b;	printf("char * c = (char*)b;   c+1:%x\n", c+1);	//6
	*c = 11;				printf("*c = 11;               c+2:%x\n", c+2);	//7
	*c = 12;				printf("*c = 12;               c  :%x\n", c);		//5
	c = (char*)b+1;			printf("c = (char*)b+1;        c  :%x\n", c);		//5
	b = (int)b+1;			printf("b = (int)b+1;          b  :%x\n", b);		//5
	c = (char*)b;			printf("c = (char*)b;          c+1:%x\n", c+1);	//6
	*c = 11;				printf("*c = 11;               c+2:%x\n", c+2);	//7
	*c = 12;				printf("*c = 12;               c  :%x\n", c);		//5
	c = (char*)b+1;			printf("c = (char*)b+1;        c  :%x\n", c);		//5
}
 
 
	return 0;
}
 
 
출력
int b = (int)&a;         b:22fed4
b = (int)b+1;            b:22fed5
int * c = (int*)b;       c:22fed5
*c = 11;                 c:22fed5
*c = 12;                 c:22fed5
 
int b = (int)&a;       b  :22fed0
b = (int)b+1;          b  :22fed1
int * c = (int*)b;   c+1:22fed5
*c = 11;               c+2:22fed9
*c = 12;               c  :22fed1
c = (int*)b+1;         c  :22fed5
 
int b = (int)&a;       b  :22fecc
b = (int)b+1;          b  :22fecd
char * c = (char*)b;   c+1:22fece
*c = 11;               c+2:22fecf
*c = 12;               c  :22fecd
c = (char*)b+1;        c  :22fece
b = (int)b+1;          b  :22fece
c = (char*)b;          c+1:22fecf
*c = 11;               c+2:22fed0
*c = 12;               c  :22fece
c = (char*)b+1;        c  :22fecf

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

익명 사용자의 이미지

비트필드 맴버에 대한 포인터 주소& 연산은 허용되지 않으므로,
1비트 주소 따윈 C에서는 불가능합니다.
C에서 메모리 객체의 최소 단위는 char형의 크기이고, 보통 8bit=1byte입니다.

귀하의 예제가 대체 뭐를 위한 것인지는 모르겠으나,
C언어에서 1bit 주소 같은건 있지도 않고,
귀하의 예제가 그것과 관련이 있지도 않습니다.

익명 사용자의 이미지

1byte 단위로 int 형의 주소를 옮기는 예제를 보이고 싶은 거라면,
x86같은 일부 CISC 프로세서에서만 가능한 예제입니다.
권장되는 테크닉이 전혀 아닌데
초보자에게 이런 코드를 보여줘서 대체 뭘 말씀하시고 싶은 건가요?

shint의 이미지

.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

익명 사용자의 이미지

SIGBUS 폴트는 일부 머신에서나 일어납니다.

대부분의 경우 문제 없어요.

kukyakya의 이미지

일부 머신에서나 일어나는 버그는 대부분의 경우 문제 없으니까 호환성 따위 신경안쓰고 그냥 써도 된다는 말씀이신가요?

익명 사용자의 이미지

제 말을 그런 식으로 왜곡하시면 곤란합니다.

막 써도 된다는 말이 아닙니다.
SIGBUS에 대한 이해가 충분하다면 써도 괜찮을 거라는 이야깁니다.

마치 unaligned pointer access를 무슨 척결해야 되는 것마냥
무조건 쓰면 안된다 - 라는 식의 논리가 웃기다는 겁니다.

===

http://cafe.daum.net/codeinside

익명 사용자의 이미지

"SIGBUS에 대한 이해가 충분하다면" 이라는 전제조건이 꽤나 비겁하다고 생각하지 않습니까?

"이해가 충분하다면" buffer overflow도 아주 유용한 테크닉이죠. 주로 공격할때에 쓰여서 그렇지.

내가 위에 쓴글 다시 보죠.
"권장되는 테크닉이 전혀 아닌데 초보자에게 이런 코드를 보여줘서 대체 뭘 말씀하시고 싶은 건가요?"

대부분의 경우 unaligned pointer access는 가능하다 하더라도 불필요한 동작을 야기합니다.
1 word를 읽을걸 2 word를 읽거나, 컴파일러가 추가적인 코드를 붙이거나...
권장되는 테크닉이 '당연히' 아닙니다.
그런데 초보자에게 '아무 추가설명 없이' 자랑스럽게 이런 테크닉을 보여준다?

뭔가 다른 일로 심기가 불편하시거나 아님 싸우고 싶으신 모양인데
그렇다고 그른걸 바르다고 하진 맙시다.

익명 사용자의 이미지

코드 성능 최적화하다 보면 unaligned pointer access를 야기할 수 있는 코드를 작성할 때도 있습니다.

직접 pointer 값을 조작해서 하지 않더라도 구조체 필드 값 접근하다 접근하는 경우도 생깁니다.

흔한 경우는 당연히 아니지만, 코딩하다 보면 분명 맞닥뜨리는 상황입니다.

싸우고 싶으신 건 제가 아니라 오히려 님이신 거 같던데요.

shint님께 뭐가 그렇게 불만이 많으신 건지.

1바이트 단위가 아닌 1비트 단위라고 적은 것은 (실수인진 몰라도) 그님의 잘못이지만, 그게 아니라 unaligned pointer access로 굳이 트집을 잡고 싶으셨나요?

지나가다 너무 심한 거 같아서 한 마디 한 겁니다.

저 님도, 저도, unaligned pointer access를 권장한다든지, 자랑스럽게 보여준 적 없습니다. 그건 님의 왜곡이에요.

무조건 unaligned pointer access가 나왔다는 이유만으로 까는 거 같아서 그거에 대한 반기를 든 겁니다.

===

http://cafe.daum.net/codeinside

익명 사용자의 이미지

> "SIGBUS 폴트는 일부 머신에서나 일어납니다. 대부분의 경우 문제 없어요."

귀하는 지금 해당 주제에 대해 충분히 알고 있지 못합니다.
그러기에 내 말이 '트집'으로 보이고, 위와 같은 말을 당당하게 말할 수 있는 것입니다.

이 쓰레드에 나 말고도 다른 분들이 써주신 내용 많으니까 천천히 다시 읽어보고
해당 검색어로 인터넷 검색도 좀 해보시길.
해당 주제를 말하면서 귀하와 같이 대담한 주장 - 아무 문제 없다 - 을 하는 사람은 없음.

귀하의 '무조건 unaligned pointer access가 나왔다는 이유만으로' 내가 깠다는 주장이야말로
지금 이 논의에 대한 무가치하면서도 저열한 왜곡임.

익명 사용자의 이미지

예. 가르침 참 고맙네요.

대부분 문제 없다 랑 아무 문제 없다 랑 같은 표현으로 해석하시는 분이셨군요.

할 말이 없습니다.

익명 사용자의 이미지

'대부분 문제 없다'라고 해도 틀립니다.

undefined behavior인건 둘째치고서라도,

다른 분들도 적어주셨듯이 그것이 허용되는 x86에서조차도 정렬되지 않은 메모리주소에 대한 접근은 공짜가 아닙니다.

내가 괜히 댁이 잘 알고 있지 못하다고 단언한게 아닙니다.

그렇게 자기 말 한두마디 비틀어서 우길 수 있는 상황이 아닙니다.

kukyakya의 이미지

물론 unaligned access가 꼭 필요한 상황이고 버스 에러가 발생하지 않는 플랫폼이라면 쓸 '수는' 있겠습니다만,

버스 에러가 발생하지 않는 플랫폼이라고 하더라도 성능 저하의 가능성이 높고 동기화 문제가 발생할 여지가 있으며 표준에서조차 undefined behavior로 정의하는데 써도 괜찮다는 얘기가 굳이 왜 나오는지 모르겠습니다.

애초에 unaligned access가 '꼭' 필요한 이유라도 있으신지 궁금합니다.

말씀하신 이유대로라면 int a = *(int*)(NULL); 도 써도 괜찮은 코드가 됩니다만...

jick의 이미지

(위에 kukyakya 님도 쓰셨지만, 이 점은 좀 강조가 필요해서...)

SIGBUS에 대한 이해만 필요한 게 아니라 C standard에 대한 이해도 필요합니다. Unaligned access는 C에서 undefined behavior로 정의하고 있습니다. 이 말은 컴파일러가 보고 "어 이 코드를 따르면 unaligned access가 발생하네? 이건 undefined behavior니까 이 코드는 절대 실행 안된다고 가정해도 되겠군! 그러면 여기서 여기까지 코드가 절대로 실행될 일이 없으니 다 들어내면 되겠네? 최적화 했다 룰루루~~" 이럴 수 있다는 말입니다.

농담 아니고 진짜로 이런 일이 일어날 수 있습니다.

그래서 unaligned access는 성능상 꼭 필요한 경우가 아니면 안 쓰는 것이 매우 좋으며 성능상 꼭 필요한 경우라고 하더라도 (원래 표준에서 허용한 기능이 아니므로) 자기가 쓰는 컴파일러가 정확히 무슨 동작을 하는지 정확히 알아보고 써야 하는 아주 위험한 기능입니다.

참고: http://stackoverflow.com/questions/28893303/is-a-misaligned-load-due-to-a-cast-undefined-behavior

아래는 Unaligned와는 약간 다른 얘기지만,

참고2: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html

중간에 이런 코드가 나오는데:

float *P;
void zero_array() {
  int i;
  for (i = 0; i < 10000; ++i)
    P[i] = 0.0f;
}

(float가 4바이트라는 가정 하에) C 컴파일러는 이 코드를 "한번에 40000바이트 0으로 덮어씀"으로 최적화할 수 있다고 합니다. 왜냐 하면 float와 float *는 서로 호환 불가능한 타입이므로 예를 들면 &P == &(P[100]) 같은 상황은 절대 생기지 않는다고 컴파일러가 가정하기 때문이죠. 실제로 그런 상황이라면 어떻게 될지는 알아서들 생각해 보시고...

bushi의 이미지

아마도 '대부분' 이라고 말하시는 근거일거라 생각되는 x86(및 x86_64) 에서 조차도 문제가 아예 없지는 않습니다.
Intel 이 배포하는 문서에 성능 저하가 일어난다고 적혀있기 때문에,
민감한 응용에선 alignment check 를 합니다.

[schoi0@sel-schoi0-d2 DOCS]$ cat -n align_test.c
     1	int main(void)
     2	{
     3	    volatile unsigned char foo[] = { 1, 2, 3, 4, 5 };
     4	    volatile int bar;
     5	
     6	    bar = *(int *)(foo + 1);
     7	
     8	    return 0;
     9	}
[schoi0@sel-schoi0-d2 DOCS]$ gcc -o align_test align_test.c -g
[schoi0@sel-schoi0-d2 DOCS]$ gdb align_test
...
Reading symbols from align_test...done.
(gdb) break align_test.c:6
Breakpoint 1 at 0x400515: file align_test.c, line 6.
(gdb) run
Starting program: /work/DOCS/align_test 
 
Breakpoint 1, main () at align_test.c:6
6	    bar = *(int *)(foo + 1);
 
(gdb) set $eflags |= (1< <18)
(gdb) c
Continuing.
 
Program received signal SIGBUS, Bus error.
main () at align_test.c:6
6	    bar = *(int *)(foo + 1);
(gdb)

제가 알기론, 단 하나의 예외가 long double 입니다.
x86 에서 12 바이트의 크기를 가지는데 align 은 8 바이트면 된다고 합니다. (x86_64 에선 16 바이트 크기, 16 바이트 align 이고요)
[schoi0@sel-schoi0-d2 DOCS]$ cat -n align_test2.c
     1	int main(void)
     2	{
     3	    volatile unsigned char foo[64];
     4	    long double bar;
     5	    
     6	    bar = *(long double *)(foo + 8);
     7	
     8	    return 0;
     9	}
[schoi0@sel-schoi0-d2 DOCS]$ gcc -o align_test2 align_test2.c -g -m32
[schoi0@sel-schoi0-d2 DOCS]$ gdb align_test2
...
Reading symbols from align_test2...done.
(gdb) break align_test2.c:6
Breakpoint 1 at 0x80483f6: file align_test2.c, line 6.
(gdb) run
Starting program: /work/DOCS/align_test2 
 
Breakpoint 1, main () at align_test2.c:6
6	    bar = *(long double *)(foo + 8);
Missing separate debuginfos, use: debuginfo-install glibc-2.18-19.fc20.i686
 
(gdb) set $eflags |= (1< <18)
(gdb) c
Continuing.
[Inferior 1 (process 22855) exited normally]
(gdb)

malloc() 의 return address alignment 가 x86 에서 8 이고, x86_64 에서 16 인 이유가 이 long double 의 alignment 때문일지도요.
익명 사용자의 이미지

1비트 주소가 진짜로 가능하다고 믿으시면... C++의 vector이 왜 다른 vector와 다르게 행동하는지 언급하면 제 손가락만 아플 것 같습니다. _msize()를 즐겨 쓸 때부터 알아봤어야 했는데...

익명 사용자의 이미지

아 중간에 글자가 사라졌네요. C++의 vector<bool>입니다.

twinwings의 이미지

HDNua 님 답변 참고하시구요.

그리고 이 밑은 사족입니다.

머신에 따라 주소의 1단위가 꼭 1byte를 의미 하지는 않습니다.

예전 잠깐 개발하던 임베디드 보드 중에 주소값 1 차이가 1 word(2byte)를 나타내더군요.

16비트 머신이었는데 이렇게 하므로서 64KB가 아닌 128KB까지 메모리를 사용할 수 있더군요.

(물론 char를 사용할 수 없으니 약간의 메모리 낭비는 있겠지만요..)

익명 사용자의 이미지

그야 당연하지요.

기계의 ISA에서 어느 레벨까지의 메모리 접근을 허용하는지에 따라 결정되는 부분입니다.

비트 단위의 메모리 접근을 허용하는 기계도 있을 수 있어요.

통상 메모리 접근의 최소 단위가 바이트라고 말하는 것은 인텔을 포함한 메이저 CPU의 ISA 기준으로 설명한 것입니다.

기실 인텔 등에서도 메모리 접근의 최소 단위가 바이트인 것은 실제로는 아니지요.

메모리 접근 단위는 Memory Buffer Register의 크기에 의해 결정되니까요. 그 이하의 단위 액세스는 두 번의 메모리 액세스를 야기하지요.

익명 사용자의 이미지

아래 댓글을 쓴 "저랑 똑같은 고민을 하시는줄 알았는데,,,,"글의 글쓴이 인데요..

"메모리 접근의 최소 단위가 바이트인 것은 실제로는 아니지요"는 맞습니다.
아래도 약간 언급하긴 했지만, 작은 단위로 데이터의 R/W를 매번 메인 메모리로 접근하는 것은
엄청난 부하를 야기하는 것이겠지요~
그래서 Cache를 사용하는 것이고, 님께서는 그것을 말씀해주시고 계시는군요^^

그런데, 메모리 접근 단위가 Memory Buffer Register의 크기에 의해 결정된다는 것은...무엇을 말씀하시는건지요..
조금만 더 부연 설명 부탁드려도 될까요? (예를 들면 어디에 위치하고 어떻게 동작하는 Register인지..)

제가 알기론 메모리의 접근 단위는 Cache Line Size로 알고 있는데,,

(음..혹시 제가 이 글들의 논점을 흐리는건 아닌지 걱정되네요,
사실 확실히 구분은 되어야 합니다. 메인메모리와 캐시메모리의 구분은!
메인메모리로 대부분 말씀하시는 것이라고 하는 것이겠지요?)

익명 사용자의 이미지

표준 C언어 기준으로는 byte의 정의 자체가 '주소지정가능한 단위'입니다.
(따라서 메모리 접근의 최소 단위가 바이트(결과적으로는 char type)라고 하는 문장은
표준 C언어 구현체에서는 기계에 상관없이 언제나 참입니다.)

말씀하신 임베디드 보드 위에서 돌아가는 C언어 구현체가 있다면
1) 1byte=16bit이다
2) 1byte=8bit이고 C언어 내부적으로는 독자적 주소체계를 쓴다
중 하나겠지요.

표준을 따르는 C언어라면 char 타입은 반드시 있어야 합니다.
그리고 기계의 구조에 상관없이 (적법한 메모리 객체에 대한) char 단위 접근은 언제나 참입니다.

익명 사용자의 이미지

위의 "저랑 똑같은 고민을 하시는줄 알았는데,,,,"글의 글쓴이 인데요..
재밋네요 KLDP, 가입해서 실명으로 활동해도 재밋을것 같아요 ㅎ

twinwings님의 경험대로라면
해당 시스템은 0x0000 을 접근하면 2Byte,
0x0001 을 접근하면 2Byte,,,, 이런 식으로 메모리가 Mapping되어져있다는 것이지요?

신기하네요.. 어째서 이런 동작이 가능한거죠...?
어떤 임베디드 보드인지 기억나시나요? 혹시 캐시 데이터를 보신건 아니신가요?
Cache가 동작하는 시스템은 예를들어 0x1000_0000을 접근하더라도 1Byte만 메인메모리에서 Read하지 않고,
Cache Line Size만큼 Cache Line Fill 하면서 0x1000_0020** 까지 Cache로 읽어 들입니다.
(**읽어오는 크기는 Cache Size마다 다릅니다.32Byte, 64Byte 등등..)
(※ Cache를 채우는 동작은 Memory Type이나 정책에 따라 상이 할 수 있습니다. 예를 들면 Memory DQ lIne, Burst Length 등등의 차이로..)

혹시 보드이름이 기억이 나시면, 한번 찾아서 분석해보고 싶은데,,
알려주실수 있으신가요?

Thanks

Anti-Lock의 이미지

일단 제가 알고 있기로는
TI사의 C2000 계열 칩이 그러합니다.
대표적으로 28335 를 찾아보시면 될겁니다.
모바일이라 정확한 칩이름을 알려드리지 못해 죄송합니다.
이칩은 업계에서 아주 대중적으로 흔히,매우,자주 사용되고 있는 칩입니다.

bushi의 이미지

MCU와 주변 장치를 뒤바꿔 오해하고 계시거나 칩 이름을 잘 못 적으신 것 같습니다.
TI 사 C2000 계열 TMS320F28335 는 FPU (single-precision)까지 가지고 있는 32bit MCU 입니다.

주변 장치들에선 흔한 경우이고, 보통은 MCU 와 연결할 때 어드레스 라인을 1bit 쉬프트시켜서 연결하죠.
MCU 측 S/W 에선 그 장치에 접근할 때 16bit I/O instruction 이 사용되도록, address align 은 2byte 가 되도록 주의를 기울여 작성합니다.
이런 것 때문에, 심지어 endian 이 고정되어 있는 플랫폼에서조차도, C struct 의 bitfield 를 디바이스 드라이버 작성 때 장치에 접근하기 위한 용도로 사용하지 않습니다. https://kldp.org/node/114347

Anti-Lock의 이미지

아마도, 저의 댓글이 어떤글에 대한 댓글인지에 대해 오해를 하신것 같습니다.
저는 C2000 계열이 16비트 CPU라고 말한것이 아닙니다.

CPU가 32비트라고 해서 메모리 버스크기가 반드시 32비트라고 단정 할수는 없습니다.
그렇다면, CPU 비트수는 언급할 필요가 없다고 봅니다.
(CPU 가 그차체로 '칩(여기서는 CPU+메모리버스+메모리(램)+기타)'이 아니니...)
CPU 비트수는 메모리 버스 크기와 일치하지 않을 수 있습니다.(적어도 그렇게 설계 가능합니다)

언급하신 칩도, sizeof(char)==sizeof(int) 이며, 16비트 크기일것 같습니다.

http://www.mcublog.co.kr/m/1559

Necromancer의 이미지

SIGBUS 거의 안일어난다는 소리는 첨 들어보네요.
MIPS, ARM, SPARC, PA-RISC, POWER... 대부분의 RISC는 다 SIGBUS 날 수 있습니다.
unaligned access 하면 즉, 4바이트 단위로 접근하는데, 메모리 주소가 4의 배수가 아닌경우 이럴 때 떨어지는게 SIGBUS입니다.
단, x86은 unaligned access를 처리하는 H/W가 있어서 발생할일 없습니다. 속도에서 패널티 먹는정도.

메모리의 최소 접근 단위는 CPU가 인식하는 메모리 주소체계와 기계어 명령 구성을 보면 알 수 있습니다. CPU 설계한 사람 맘입니다.
8bit가 1byte가 된데는 컴퓨터가 처음 나온 영어권의 모든 문자를 이 비트로 다 표현할 수 있고, 비트 단위로 일일이 주소 매기면 비효율적인 경우가 많으니 보통은 자주 쓰이는 최소단위인 byte 단위로 메모리를 사용할 수 있도록 만들고, 비트단위 처리가 필요할 경우에 한해서 특별한 처리하게 만든겁니다.
보통 주소는 byte 단위로 매기고, 접근단위도 8bit=1byte를 최소로 해서 2byte, 4byte, 8byte, 16byte... x2 하는 식으로 하는 경우가 많죠.

Written By the Black Knight of Destruction

익명 사용자의 이미지

사진에 첨부된 코드는 메모리 주소의 값을 나타내는 코드입니다.
메모리 주소는 데이터를 가리키는 값입니다.
배열은 데이터가 일렬로 저장되기 때문에 32bit인 int형은 8bit짜리 주소를 4개씩 건너뜁니다.
메모리 주소의 값과 메모리 주소의 크기 값을 헷갈리신것 같습니다.

ehaakdl의 이미지

16진수 한자리당 4비트 차지!

어렵아무개오오의 이미지

32비트 시스템에서 4GB 이상 주소를 못 담죠.
그래서 32비트 시스템은 4gb 이상 램을 못 달고 달아도 쓸 수 없죠.그림판 무한 띄우면 죽음.
그래서 64비트 시스템이 나와서 램 제한 없죠.
4바이트로 2^33-1 =4GB 크기까지 표현 가능하니
8바이트로 2^64-1 까지 표현가능.
2바이트로 2^16-1= 65332 byte 표현가능. 즉 16비트 메모리 주소로는 65메가 넘으면 죽어요. 물론 프로그래밍으로 여러개 메모리 컨트롤은 가능하지만요. 주소로는 표현불가임.
8비트는 255바이트만 가리킬 수 있어요.
이제 "메모리 1개 당 몇 바이트인가?"는 주소가 곧 바이트 크기다.라고 하겠죠.
메모리 읽기쓰기를 타이밍 차트 명령으로 전달할 때, 메모리 주소의 1바이트만 읽는다면 1비트의 주소겠죠.
그냥 c와 같습니다. "주소의 차이수=바이트수" 입니다.
그리고 메모리 읽기에 대한 리턴 크기는 메모리 제작한 사람이 버스 크기를 얼마나 만들었냐에 달렸죠.
주소 읽으라고 하면 무조건 1바이트, 2바이트씩 리턴하는 것도 있고, 4바이트, 8바이트 짜리도 있어요.거기서 우리가 원하는 주소가 가리키는 값을 가져오는거 뿐이에요. 버스수가 작으면 시간이 걸릴거고. 많으면 적게 걸리겠죠. EEPROM은 바이트 단위로 타이밍을 보내는 칩이 많아요. 사실상 메모리나 디스크나 똑같습니다.
초당 읽기속도 쓰기 속도가 높은 제품들은 읽고 쓰는 단위가 큰 겁니다. SSD타이밍 차트가 1바이트씩 읽고 1바이트씩 쓴다면 속도가 나겠습니까? ㅎㅎㅎ

뭔가했더니ㅡㅡ의 이미지

보니까 메모리에서 물리적 타이밍 차트가 정해져있고
메모리를 지원하는 OS는 거기에 맞춰 읽고 써 줍니다.
전에도 디스크랑 메모리랑 별차이 없군요.
CPU는 빠르고 메모리는 느립니다. 속도 차이가 나죠.
그리고 메모리마다 읽기 쓰기 단위가 정해져있고
고급램은 읽기쓰기 단위가 몇가지의 타이밍 차트로 제공하는 제품들이 있습니다. 즉 램 스펙에 따라 다르게 동작하죠. 이를 지원하는 OS는 골아프겠지만요.
읽기쓰기 단위가 통상 2의 배수인데 램에 따라 그 크기가 다릅니다. 저장단위가 다른거죠. 사용자가 2의 배수 또는 4의 배수 8의 배수로 메모리를 안쓴다고 합시다.
구조체가 7등의 prime으로 되어있다 칩시다. CPU가 어디 위치인지 정확히 나눌 수 있습니까? 또 정확한 위치계산을 해서 가까운 번지에서 일정크기를 리딩하고 다시 읽을 위치로 점프해서 값을 돌려줘야합니다. prime 넘버만 되게 계속 번지수를 줘 봅시다. 읽기 쓰기 타이밍이 맞지않으면 cpu가 어떻게 될까요?
빠르고 큰 주소를 제공하는 메모리는 액세스할수록 프라임 넘버에 해당하는 랜덤한 주소계산을 하도록하면 죽지않을까요? 정확한 원인을 쉽게 설명할분 계신가요?

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.