Heap 인지 Stack 인지 알수 있는 방법 좀 부탁합니다.

micom96의 이미지

C 에서 해당 변수가 heap 인지 stack 변수인지 혹은 global 변수인지 알 수 있는 standard 함수가 있는지 궁금합니다.

왜 사용을 하냐 하면

void test(char* value) 호출할때 char buf[80]; 혹은 char* buf; 를 넘겨줄 수 있잖아요

이때 stack 변수 인지 heap 변수 인지 알고 싶거든요

그럼 부탁드립니다.

simpid의 이미지

코드에서 변수가 어떤 위치에 만들어 져 있는지 알 수 있는 함수는 없고..
어떤 꽁수로 알아 낼 수 있을지는 모르겠지만...
프로그램을 작성하는 프로그래머 자신은 알고 있지 않습니까?

함수 밖에서 선언했다면 global
함수 안에서 선언했다면 stack
함수 안에서 선언하면서 static을 줬다면 global
malloc등으로 할당했다면... heap

프로그래머 자신은 알고 있을텐데...
님의 경우 현재 상황이 런타임중에 결정할 필요가 있나보죠?

bugiii의 이미지

Meyers 의 More Effective C++
Item 27: Requiring or prohibiting heap-based objects.

변수의 위치가 힙,스택,전역인지를 판단하기는 힘들다는 문제점과 함께 피해야 한다고 하네요. 그런 구분이 필요한 설계를 피하는 것이 더 낫지 않을까 합니다만...

그럼, 이만...

micom96의 이미지

네 그래야 겠네요

답변 주신분들 감사합니다.

pynoos의 이미지

프로그램에서는 어느 위치에 있는지 확인하여 action을 하는 것은 삼가야합니다.

다만 디버깅할때는 어디에 있는지 감을 갖는 것은 좋죠.

static 변수하나 만들고, 그 변수의 pointer와 상위 8 bit 정도 비교하시면 될 것입니다.

그렇게 되면, stack인지 아닌지정도는 구별할 수 있으며,

BSS 와 Heap은 main 시작하자 마자 sbrk 명령으로 현재 할당받은 data segment의 마지막 값을 구해 놓고 그것보다 작으면 BSS, 크면 Heap이라 추정할 수 있습니다.
단, 가정은
main 시작전에 Data Segment 메모리가 적당히 잡혀있지 않다.
main 이후 최초 만나는 malloc 은 메모리를 더 할당 받는다
입니다.

일반적으로,
BSS < 최초 Data Segment 최대 번지 < Heap < Stack 순입니다.

재미로 돌려 봤는데, 눈요기 하시라고 필요하신분도 있을 것 같애서 결과를 올려 봅니다.

#include <unistd.h>
#include <stdio.h>

int bss;

int main()
{
        int stack;
        int * heap;
        void * beg;
        beg = sbrk(0);
        heap = (int *) malloc(4);
        printf("BSS   Sample: %p\n", & bss );
        printf("Heap  Begin : %p\n", beg );
        printf("Heap  Sample: %p\n", heap );
        printf("Stack Sample: %p\n", & stack);
        return 0;
}

제가 테스트해본 결과로는

linux kernel 2.4.2 (GLIBC_2.2.3) 에서

BSS   Sample: 0x8049708
Heap  Begin : 0x804970c
Heap  Sample: 0x8049718
Stack Sample: 0xbffffa64

HPUX 10.20 에서

BSS   Sample: 40001160
Heap  Begin : 40001164
Heap  Sample: 40003170
Stack Sample: 7b03a9c0

Solaris 2.7 (x86)에서

BSS   Sample: 804a754
Heap  Begin : 804a758
Heap  Sample: 804a768
Stack Sample: 8047cf4

위와 같이 나왔구요.

AIX 4.3.3 에서는

BSS   Sample: 200007f0
Heap  Begin : 20010800
Heap  Sample: 20000818
Stack Sample: 2ff229f8

와 같이 나오는 군요. 맨 위 가정에 위배된다고 생각합니다.

아마 AIX 는 main 이전에 메모리 확보를 어느정도 해놓고, 최초 malloc 에서 그 안의 영역이 사용되나봅니다.

다시한번 강조하는 것은 어디까지나 구현에 따른 경험을 이용한 debugging에서 사용되어야지, critical path에 사용되어서는 안됩니다.

코드상 Heap Begin이라고 썼는데, 정확한 표현이 아닙니다.

맹고이의 이미지

제가 지금까지 본책에는.. (몇권 안됩니다;; )
stack, heap, static .. 이렇게 메모리가 나눠진다고 보았거든요
BSS라는건.. 제가 말하는 static영역이랑 같은건가요?

제가 보는책은 너무 기초책이라서 그런건지..
인터넷에서 찾아보면 code, data, bss, stack, heap, env
이렇게 많던데.. 막상 자세한 설명은 잘 못찾겠습니다..

Quote:
=================================================================
| init | | | |
text(code) | data | bss | heap | virtual memory space | stack
=================================================================
low high

=================================================================
stack : char buf[1024];
heap : char *buf;
buf = malloc(1024);
bss : static char buf[];
initialized data : static char buf[] = "test";
=================================================================


이정도까진 찾아봤습니다만..
code, data, env 에 관해 설명좀 부탁드립니다 ..
아니면 어디에서 이것에 관한 자료를 찾아볼수있을까요..?
pynoos의 이미지

Text 는 function 내용이 들어가는 곳
DATA는 Readonly value 들이 들어가는 곳
BSS는 전역함수 혹은 함수내 static 변수들이 들어가는 곳 (답변이네요.. ^^)
ENV 는 프로그램 실행시 환경변수가 들어가는 곳

입니다.

이중에서 실행파일내부에는 text, data, bss 만 들어 있으며,
heap, stack은 실행중에 가변되는 잘 알려진 특성이 있고,
env 는 stack 보다 더 큰 주소에 위치합니다.
BSS는 대개 object에서 data 길이만 잡혀있습니다.

특성을 나열하자니 한도 끝도 없겠네요...

data bss stack heap 정도의 키워드를 주니 구글 선생님이 많은 사이트를 알려주는 군요

cedar의 이미지

bugiii wrote:
Meyers의 More Effective C++
Item 27: Requiring or prohibiting heap-based objects.

변수의 위치가 힙,스택,전역인지를 판단하기는 힘들다는 문제점과 함께 피해야 한다고 하네요. 그런 구분이 필요한 설계를 피하는 것이 더 낫지 않을까 합니다만...

그럼, 이만...

bugiii님의 인용과 pynoos 님이 소개한 방법에 대한 몇 가지 첨언을 해보죠.

pynoos님의 실험처럼, 시스템마다 힙, 스택, 전역 메모리 공간의 배치 방법은 서로 다릅니다. 코드의 이식성을 심각히 위배하는 방법이죠.
물론 대부분의 시스템이 스택 메모리는 최상위 주소에서 시작하여 하위로 자라나가고, 힙과 전역 메모리는 최하위 주소에서 시작하여 자라나가지만(이것은 물론 ANSI 표준에 정해져 있는 것이 아닙니다!), AIX의 예외에도 보듯이 힙과 전역 메모리의 위치는 시스템마다 다릅니다.
게다가 sbrk라는 POSIX 함수를 호출해야 하지요. 예를 들어 WIN32라면 다른 방법을 사용해야 한다는 얘기입니다.

또한 이런 문제점 때문에, 변수가 스택에 있는지를 체크하려면
임의로 선언한 정적변수(pynoos님의 코드에 있는 'bss' 변수)와 비교하는 방법은 시스템에 따라 정확하지 않습니다.
다음과 같이 스택에 임의의 변수를 선언한 후 비교하여야 합니다.

bool onStack(const void* address)
{
  char onTheStack;
  return address > &onTheStack;
}

결국 More Effective C++, Item 27에서 제시한 내용을 정리하면,
변수의 위치가 힙, 스택, 전역인지를 이식성 있게 판단하는 것은 불가능합니다.

보통 이렇게 객체가 힙에 있는 지를 체크하는 경우는 'delete this'를 해도 되는 지를 체크하기 위한 것이 대부분입니다. 즉, 이 포인터에 delete를 해도 되는 지를 판단하는데 사용하는 것이죠.
반면에 기본 제공 타입에서는 변수가 힙에 생성되었는가를 판단할 필요가 없는 것이 정상적인 프로그램입니다.

MEC++에서는 int, char와 같은 기본 타입이 아니라 사용자 정의 클래스인 경우에, 'delete this'를 해도 되는 지를 판단할 수 있는 이식성 있는 방법을 소개하고 있습니다.
operator new와 operator delete 를 오버로딩하여, operator new에서 반환한 포인터를 별도의 컨테이너(이 책에서는 std::list를 사용했습니다.)에 넣고 관리하는 방식으로 해결한다는거죠.

MEC++은 그 외에도 객체를 힙에만 생성되게 한다던가, 힙에 생성되지 못하게 하는 이식성 있는 방법을 소개하고 있습니다.
개인적으로는 MEC++에서 가장 재미있던 항목 중 하나였습니다.

맹고이의 이미지

pynoos님 감사합니다.. :D
검색을 좀 더 해볼걸 그랬네요;;
이제 자세한 내용은 구글선생님께 여쭈어 보겠습니당..ㅎㅎ 8)

pynoos의 이미지

제가 제안한 상위 8 bit 비교방법에 대한 반증은 Solaris의 예에서 바로 나왔군요.
stack 에 있는지에 조사하는 방법에 대해 cedar 님의 방법에 동의 합니다. :lol:

재미로 그 함 수를 좀 더 줄이자면..

int onStack( const void * address )
{
        return (address > (const void *) &address); 
}

그리고 AIX의 예가 heap과 전역 메모리의 순서가 다른 OS와 다르다고 생각되지는 않습니다. 좀더 테스트 해봐야겠군요.
귀찮아서.. 나중에 시간날 때... -.- :wink:

단순 프로그래밍에서 디버깅을 심도 있게 해야할 때 만났던, 좋은 주제였습니다.

서지훈의 이미지

요즘 이 문제때문에 아주 골치를 앓고 있는데...
제가 이제까지 모은 정보를 좀 추가를 하면...

_참고

extern char _end;
extern char **environ;
extern HANDLE _crtheap;

linux - linux는 stack/heap을 공유해서 사용함으로 heap begin과 stack begin을 중간으로 잘라서 사용하시면 그럭저럭 잘 맞습니다.

heap begin: &_end
stack begin: environ

HP-UX B.11.11 9000/800

heap begin: &_end
heap end: 0x4ffcf778 (추정치)
stack begin: environ

SunOS 5.9 sun4u

heap begin: &_end
heap end: 0x90e48608 (추정치)
stack begin: environ

AIX 1 00572BED4C00

heap begin: &_end
heap end: 0x27fdbaa8 (추정치)
stack begin: environ

Windows_NT x86 - 일반 데스크탑

heap begin: _crtheap (text, data segment가 앞쪽에 붙어 있음)
heap end: 0x7FFFFFFF
stack begin: 0x0012FFFF
stack end: 0x00030000

위 추정치는 아주 근사치이니 그냥 사용 하셔도 무방할겁니다.

윈도우즈 노트북(XP)
heap1
stack
heap2
노트북은 위와 같은 구조로 아주 우끼게 되어 있습니다.
참고 하시길...

혹시나 여기에 정보 추가 해주실분... 추가 해도 무방합니다.
각 OS의 stack의 끝을 알고 싶습니다.
정보를 좀 더 찾아야 할듯...

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <beer.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

lovian의 이미지

노트북은.. 참 새롭군요!!
-----------------
한글을 사랑합니다.

-----------------
한글을 사랑합니다.

sjpark의 이미지

노트북이 아니라 XP가 웃기게 되어 있는거겠죠.. ;)

http://nicesj.com

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.