포인터 변수 주소와 일반 변수 주소의 차이는 왜 12바이트인가요?
글쓴이: wtwon / 작성시간: 수, 2017/05/24 - 5:10오후
안녕하세요, 포인터를 복습하는 도중에 의문이 들어 질문글 올립니다.
int b = 10; int *p1 = &b; printf("b의 주소 : %x\n", &b); printf("p1의 주소 : %x, p1의 내용(b의 주소) : %x\n", &p1, p1);
위의 코드의 결과를 windows10 - visual studio 2015에서 출력하면,
b의 주소와 p1의 주소는 항상 12바이트의 차이를 가집니다.
결과는 다음과 같았으며,
b의 주소 : eff79c
p1의 주소 : eff790
p1의 값(b의 주소) : eff79
메모리에 들어간 값을 살펴보니 아래와 같았습니다.
0x00eff790 : 9c f7 ef 00 cc cc cc cc cc cc cc cc 0a 00 00 00
0x00eff7a0 : cc cc cc cc b8 f7 ef 00 5e 22 18 00 01 00 00 00
포인터에 b의 주소가 들어간 것은 이해가 갑니다.
그리고 b의 주소를 찾아가면 정수 10(0a 00 00 00)이 들어간 것도 이해가 갑니다.
그런데 왜 항상 이 두 주소의 차이가 12가 나는지 이해가 가지 않습니다...
제가 무엇을 놓치고 있는지 알려주시면 감사하겠습니다!
File attachments:
첨부 | 파일 크기 |
---|---|
codeCapture.PNG | 52.37 KB |
Forums:
음.. 먼저 sizeof(int)와 sizeof
음.. 먼저 sizeof(int)와 sizeof(int *)를 해보시기 바랍니다.
네, 해보았습니다.
sizeof(int) : 4
sizeof(int *) : 4
각각 4가 나옵니다.
음 ..
https://stackoverflow.com/questions/25442458/why-are-consecutive-int-data-type-varaiables-located-at-12-bytes-offset-in-visua
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
감사합니다.
감사합니다!
늘 애용하지만 stackoverflow쪽을 찾아볼 생각은.. 마땅한 검색 키워드를 떠올릴 수도 없었습니다.
해당 글의 답변을 보니깐, local/block object(변수)들은 빈공간 없이 할당되지 않는 이유는 정의되지 않은 동작이기때문이라네요. 그리고 compiler의 build옵션에 따라 이런 현상(변수간 주소 간격)이 발생할 수 있다는데, 제가 제대로 이해하고 있는게 맞나요?
****
stackoverflow의 답변에 따라 build option에서 debug모드를 release모드로 바꾸니깐
각 변수의 주소 값이 빈공간없이 붙어서 나오네요.
포인터 변수 뒤로 나열되는 cc cc cc cc cc cc cc cc는 초기화되지 않은 stack memory를 표현하는 magic number라고 합니다.
...
stackoverflow의 해당 글의 답변이 좀 오해하기 쉽게 쓰여져 있는 것 같아서 몇 마디 덧붙입니다.
Local 변수를 컴파일러가 할당할 때 빈공간이 생기는 이유가 "정의되지 않은 동작"은 아닙니다. 정확히 말하자면 C/C++ 표준은 로컬 변수를 컴파일러가 어떻게 배치해야 할지에 대해 아무런 규칙을 정해놓고 있지 않습니다. 어떻게 하든지 컴파일러 마음대로입니다.
하지만 int a, b; 처럼 정해놓고 "이렇게 하면 b가 a 다음이니까 주소가 4바이트 차이나겠지?"라고 가정하여 코드를 짜면, 그게 바로 *정의되지 않은 동작*이 되는 것입니다.
심지어 일단 주소를 찍어본 다음 "아 이 컴파일러에서는 항상 12바이트 차이가 나는구나, 그러면 a의 주소를 알면 항상 12를 더하면 b의 주소가 되겠지?"라고 생각해서 코드를 짜도, 역시 *정의되지 않은 동작*이 됩니다. 이런 코드를 주면 컴파일러가 "음하하 정의되지 않은 동작 발견!" 하고 무슨 짓이든 할 수 있습니다. 함수의 내용을 통째로 날려 버린다든지... (농담 아닙니다. 진짜로 재수없으면 그런 일이 발생합니다.)
아하..
감사합니다. 덕분에 *정의되지 않은 동작*에 대해 이해(?)했습니다!
표준이 모든 것을 커버하고 있지 않네요.(할 수 없는거겠죠..?)
글쎄요. 정말로 할 수 없는 경우도 있겠지만, 사실
글쎄요. 정말로 할 수 없는 경우도 있겠지만, 사실 이 경우는 할 수 있지만 안 한 경우입니다.
예컨대 "지역변수를 스택에 올릴 때는 선언된 순서대로, 최대한 가깝게 붙여서 올린다" 따위의 규칙을 만들 수도 있었지요.
하지만 지역변수의 메모리 레이아웃도 나름 수행 성능에 영향을 주는 부분이므로, 컴파일러가 상황에 따라 적절하게 구성할 수 있도록 재량권을 부여한 것입니다.
그렇군요..
그렇군요..답변 감사합니다^^
음 ..
local/global variable 들이 어떤 순서로 배치되어 있는가에 대한 것은 잊어 버리세요.
그건 표준도 없고 컴파일러 또는 buffer overflow protection 과 같은 기능에 따라 다르기 때문에..
그걸 의식해서 코드를 작성하는 순간, undefined behavior 가 되어 버립니다.
VS 의 debug mode 에서 uninitialized memory 에 대한 부분은 아래 링크 참조.
https://stackoverflow.com/questions/370195/when-and-why-will-an-os-initialise-memory-to-0xcd-0xdd-etc-on-malloc-free-new
참고로 stack alignment 에 대해서는 잘 알아 두시는 게 좋습니다.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
음..
감사합니다.
공부할수록 이런 부분때문에 어려운게 아니라 재밌네요:)
stack alignment는 찾아보겠습니다!
아 ..
byte alignment (data structure alignment) 를 언급하는 걸 깜빡했네요.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
확인했습니다^^
말씀해주신 것을 아래에서 확인했습니다.
https://stackoverflow.com/questions/672461/what-is-stack-alignment
질문자님은 무엇을 공부하고 계신가요?
질문자님은 무엇을 공부하고 계신가요?
지금 C언어 "활용"을 공부중이고, 변수의 주소를 취하여 포인터에 저장하거나 출력하는 용법을 연습하고 계신가요?
아니면 C언어 "구현"을 공부중이고, 지역 변수를 적절히 구현하기 위한 컴파일러 혹은 시스템의 메커니즘을 살펴보고 계신가요?
후자라면 유효한 질문이고 논의를 더 이어나갈 의미가 있는 것입니다.
전자라면, 지금 질문자님은 뭔가를 놓치신 게 아니라 쓸데없는 걸 붙잡고 계신 겁니다.
어느 쪽인지 확실히 해 주셔야 더 자세한 답변을 드릴 수가 있겠지요.
활용에서 구현으로 넘어가고 있습니다.
말씀해주신 것을 기준으로 생각해보니 "활용"에서 "구현"으로 넘어가는 과정같습니다.
이전의 공부는 그냥 사용하는 것에서 그쳤다면, 지금의 공부는 왜 그렇게 동작하는지를 알고싶은 지적인 동기가 큽니다.
전공이 컴퓨터쪽임에도 불구하고 다 알지 못해 늘 찾아보려 애쓰고 있습니다.
번거로우시겠지만, 자세한 답변을 부탁드립니다. 항상 귀한시간 내셔서 답변해주시는 분들의 노고에 감사드립니다.
댓글 달기