인프런 커뮤니티 질문&답변

swing-by님의 프로필 이미지
swing-by

작성한 질문수

홍정모의 따라하며 배우는 C언어

9.17 포인터 변수의 크기

메모리의 '첫 번째 주소' 및 byte 단위 메모리 공간의 저장 순서에 대한 질문

해결된 질문

작성

·

502

0

'9.17 포인터 변수의 크기' 강의를 보고, 의문이 생겨 질문 드립니다.  예를 들어, 다음과 같은 코드가 있습니다.
int a = 4;
float b = 4.0f;
double c = 5.0;

int *ptr_a = &a;
float *ptr_b = &b;
double *ptr_c = &c;

Q1. 포인터 변수(ptr_a)가 변수(a)에 대하여 저장하는 첫 번째 주소란, 그 변수(a)가 memory에 저장될 때, 가장 마지막에 저장되는 1 byte 메모리 공간의 주소를 의미하는 것이 맞나요?

Stack memory에 data가 저장될 때에는 High address로부터 Low address방향으로 저장된다고 알고 있습니다.

포인터는, 변수가 접근하는 메모리 공간의 첫 번째 주소를 저장하는데, 여기서 Memory를 살펴본 바, 첫 번째 주소란, 변수(a)가 stack에 저장될 때, 마지막으로 저장된 1 byte 메모리 공간으로 이해됩니다.

그리고가장 먼저 저장된 변수인 a의 주소는 bc보다 높은 주소에 위치하고,b의 주소는 c보다 높은 주소에 있습니다.

그렇다면, 변수(a)의 4 byte짜리 메모리 공간들에 대해서도 저장될 때, 가장 먼저 저장되는 메모리 공간은 나머지에 비해 높은 주소에 위치한다고 추론할 수 있습니다.

그러므로 포인터가 저장하고 있는 주소값, 즉 그 변수(a)의 첫 번째 주소란, 가장 마지막에 저장되는 1 byte 크기의 메모리 공간이라고 이해하고 있습니다.

 

Q2. x64에서 debugging을 실행할 때, 가장 나중에 저장되는 변수가 가장 높은 주소를 가지고 있는데, 왜 그렇습니까?

x86으로 실행했을 때와 마찬가지로, stack에 쌓이는 메모리 공간들의 주소는 from high to low이어야 한다고 알고 있습니다.

x64로 디버깅을 해보니, 먼저 저장되는 변수 자체의 메모리 공간이 저장되는 순서는 high to low 순으로 주소를 가지지만, 각 변수의 첫 번째 주소를 참고해보면, 이상한 점이 있습니다.


가장 마지막에 저장된 변수 c가 가장 높은 주소값을 가지고 있다는 것입니다.

stack에 저장되는 메모리들의 주소는 가장 높은 메모리 주소부터 낮은 메모리 주소의 방향으로 저장되는데, 여기서는 x86 환경에서 memory 확인했을 때와 달리 정반대입니다.

왜 그럴까요?

 

답변 2

1

swing-by님의 프로필 이미지
swing-by
질문자

2022. 06. 20.

혹시 다른 분들도 헷갈리시거나 그러실까봐 배운 것을 활용해서 자문자답해봅니다. :)

 

Q1. 포인터 변수(ptr_a)가 변수(a)에 대하여 저장하는 첫 번째 주소란, 그 변수(a)가 memory에 저장될 때, 가장 마지막에 저장되는 1 byte 메모리 공간의 주소를 의미하는 것이 맞나요?

아니다. pointer가 저장하는 memory address는, 변수 a의 first address를 의미한다.
그렇다면, a의 first address는 무엇일까?

Little Endian인 x86 intel CPU architecture에서는 Low address에 있는 data가 Least Significant Byte에 저장된다. (bit-value 역시 least significant bit에서부터 저장된다.)

아래의 스크린 샷에서 a는 4 byte의 size를 가진다.
그러므로, byte order를 나타내자면, [MSB] 00 00 00 04 [LSB]가 된다.
little endian인 현재의 computer에서 data가 저장되는 순서는, low address에 있는 byte data가 먼저 저장되므로, 0x004ffbc0이 가리키는 memory space 04가 먼저 저장되었다.

그러므로 pointer ptr_a가 저장하는 a의 first address는 가장 먼저 저장된 공간을 의미한다.

 

 

(질문 내용 중)

그리고가장 먼저 저장된 변수인 a의 주소는 bc보다 높은 주소에 위치하고,b의 주소는 c보다 높은 주소에 있습니다.

그렇다면, 변수(a)의 4 byte짜리 메모리 공간들에 대해서도 저장될 때, 가장 먼저 저장되는 메모리 공간은 나머지에 비해 높은 주소에 위치한다고 추론할 수 있습니다.

 

Data가 어떤 memory block에 저장될 때는 little endian방식으로 저장되었다.

[MSB] 00 00 00 04 [LSB]

'04'가 low address인 byte이므로 먼저 저장된 것이다.

그렇게 저장된 data object의 memory address는 Linux OS / GCC Compiler 기준으로 stack에 할당될 때, memory address가 high to low의 방향성을 가지게 된다.

즉 먼저 저장된 변수a가 나중에 저장된 포인터 변수 ptr_a보다, high address를 가진다는 것이다.

 

하지만 이 방향성이 변수 a에 대하여,  'high address에 있는 '00'이 먼저 저장된다'는 것을 의미하지는 않는다. Data를 저장하는 방식인 endianness와 memory layout에서 address의 방향성을 혼동하지 말자.

 

 

Q2. x64에서 debugging을 실행할 때, 가장 나중에 저장되는 변수가 가장 높은 주소를 가지고 있는데, 왜 그렇습니까?

 

(홍정모 교수님 말씀대로,  OS / Compiler 에 따라 다르기 때문이다.

Stack과 Heap에, data들이 memory를 할당받을 때, 그 address의 방향성이 다르다.

이 variable들은 모두 stack에 allocation된다.
Linux OS / GCC 기준으로 from high to low address의 방향성에 따라 할당될 것이다.
그렇다면,

[High Address Memory]a, b, c, ptr_a, ptr_b, ptr_c[Low Address Memory]

인 방향성을 보일 것이다.

Linux OS계열인 Ubuntu OS / Clang Compiler를 활용하는 Online compiler replit에서 확인해보자.)

 

(먼저 stack에 저장된 a가 High Address에 위치하고 있다.
나중에 저장된 ptr_c는 Low Address에 위치하고 있다.)

 

 

1

홍정모님의 프로필 이미지
홍정모
지식공유자

안녕하세요? 지금 질문하신 내용들은 프로그래밍 언어의 범위를 넘어서 운영체제와 연관이 되는 부분입니다. 저도 운영체제나 컴파일러 전공자가 아니지만 궁금하신 내용과 관련있을 만한 내용들을 알려드리자면,

1. Endianness https://ko.wikipedia.org/wiki/%EC%97%94%EB%94%94%EC%96%B8

메모리에 데이터를 어떤 순서로 기록할지인데 우리의 직관과 다릅니다. 중간의 그림 보시면 쉽습니다. 강의 후반부에서 잠깐 다뤘던 것으로 기억합니다.

2. 스택

윈도우와 리눅스가 메모리 사용법이 다릅니다. 우리가 흔히 알고 있는 상식들은 리눅스 기준입니다. 그래서 강의 후반부에서는 리눅스에서도 주소를 보여드린 것으로 기억합니다.

도움이 되었기를 바랍니다.

swing-by님의 프로필 이미지
swing-by
질문자

답변해주신 내용들 알아보니, 새롭게 만나게 되는 내용들도 많은 것 같습니다. 
나중에 C언어 강의 끝나고 복습하면서 다시 돌아봐야겠습니다.
답변 감사드립니다!  

swing-by님의 프로필 이미지
swing-by

작성한 질문수

질문하기