내 변수는 C의 어디에 저장됩니까?


156

메모리가 전역 변수, 정적 변수, 상수 데이터 유형, 로컬 변수 (함수로 정의 및 선언 됨), 변수 (주 함수에서), 포인터를 수행하는 데이터, 힙, 스택 및 코드의 네 가지 세그먼트로 나누어지는 것을 고려하여 및 malloc 및 calloc을 사용하여 동적으로 할당 된 공간이 메모리에 저장됩니까?

나는 그들이 다음과 같이 할당 될 것이라고 생각합니다.

  • 전역 변수 -------> 데이터
  • 정적 변수 -------> 데이터
  • 상수 데이터 유형 -----> 코드
  • 지역 변수 (함수에서 선언되고 정의 됨) --------> stack
  • 메인 함수에서 선언되고 정의 된 변수 -----> 힙
  • 포인터 (예 : char *arr, int *arr) -------> 힙
  • 동적으로 할당 된 공간 (malloc 및 calloc 사용) --------> stack

나는 C 관점에서만 이러한 변수를 언급하고 있습니다.

C를 처음 접했을 때 내가 틀렸다면 바로 정정하십시오.


4
타입은 메모리에 저장되지 않습니다.

5
main또 다른 기능입니다. malloc다른 곳에서와 달리 변수가 없으면 스택에갑니다 .
simonc

4
포인터는 (보통) 스택에 저장됩니다. 그들이 가리키는 메모리 (일반적으로 malloc / calloc을 통해 할당)는 힙에 있습니다.
jpm

3
동적 할당 공간 (malloc, calloc 사용) --------> heap
One Man Crew

3
main 함수에서 선언되고 정의 된 변수 -----> stack
One Man Crew

답변:


217

당신은 이러한 권리 중 일부를 가지고 있지만 질문을 작성한 사람은 적어도 하나의 질문에 대해 당신을 속였습니다.

  • 전역 변수 -------> 데이터 (올바른)
  • 정적 변수 -------> 데이터 (정확한)
  • 상수 데이터 유형 -----> 코드 및 / 또는 데이터. 상수 자체가 데이터 세그먼트에 저장 될 때 문자열 리터럴을 고려하고 이에 대한 참조가 코드에 임베드됩니다.
  • 지역 변수 (함수에서 선언되고 정의 됨) --------> stack (correct)
  • main함수 에서 선언되고 정의 된 변수 -----> heap 도 스택 (선생님이 당신을 속이려고했습니다)
  • 문맥에 따라 포인터 (ex : char *arr, int *arr) -------> 데이터 또는 스택. C를 사용하면 전역 또는 static포인터 를 선언 할 수 있으며이 경우 포인터 자체가 데이터 세그먼트에있게됩니다.
  • 동적으로 할당 된 공간 (사용하여 malloc, calloc, realloc) --------> 스택

"스택"을 공식적으로 "자동 스토리지 클래스"라고합니다.


6
또한 힙은 공식적으로 전혀 호출되지 않습니다. 할당 된 메모리는 어딘가에서 나옵니다. 그 "어딘가"의 표준에는 이름이 없습니다.
Steve Jessop

6
일부 시스템 (Linux 및 * BSD)에도 alloca이와 유사한 기능이 malloc있지만 스택 할당은 수행됩니다.
Andreas Grapentin

메소드 안에서 선언 된 const 변수는 어디로 가나 요?
Mahori

@Ravi 나머지 상수가 같은 곳 (위의 3 번 지점).
dasblinkenlight

GCC 4.8.1을 사용하고 있으며 const 변수를 DATA 세그먼트의 main에 로컬로 저장하지 않는 것 같습니다. 다음은 이러한 3 개의 프로그램에 대한 코드 및 메모리 맵입니다. 코드 1 : int main (void) {// char a [10] = "HELLO"; // 1 // const char a [10] = "HELLO"; // 2 return 0; } 위의 메모리 맵 : 텍스트 데이터 bss dec 16 진 파일 이름 7264 1688 1040 9992 2708 a.exe 2의 메모리 데이터 맵 : 텍스트 데이터 bss dec 16 진 파일 이름 7280 1688 1040 10008 2718 a.exe 3의 메모리 맵 : 3에 대한 메모리 맵 : 텍스트 데이터 bss dec hex 파일 이름 7280 1688 1040 10008 2718 a.exe
Mahori

124

해당 메모리 세그먼트에 대해 알고 싶은 미래의 방문자를 위해 C에서 5 개의 메모리 세그먼트에 대한 중요한 사항을 작성하고 있습니다.

일부 머리 위로 :

  1. C 프로그램이 실행될 때마다 일부 메모리가 프로그램 실행을 위해 RAM에 할당됩니다. 이 메모리는 자주 실행되는 코드 (이진 데이터), 프로그램 변수 등을 저장하는 데 사용됩니다. 아래 메모리 세그먼트는 동일한 내용에 대해 설명합니다.
  2. 일반적으로 세 가지 유형의 변수가 있습니다.
    • 지역 변수 (C에서 자동 변수라고도 함)
    • 글로벌 변수
    • 정적 변수
    • 전역 정적 또는 로컬 정적 변수를 가질 수 있지만 위 세 가지가 상위 유형입니다.

C의 5 가지 메모리 세그먼트 :

1. 코드 세그먼트

  • 텍스트 세그먼트라고도하는 코드 세그먼트는 자주 실행되는 코드를 포함하는 메모리 영역입니다.
  • 코드 세그먼트는 종종 버퍼 오버 플로우 등과 같은 버그를 프로그래밍하여 오버라이드 될 위험을 피하기 위해 읽기 전용입니다.
  • 코드 세그먼트에는 로컬 변수 ( C에서 자동 변수라고도 함 ), 전역 변수 등과 같은 프로그램 변수가 포함되어 있지 않습니다 .
  • C 구현에 따라 코드 세그먼트에는 읽기 전용 문자열 리터럴도 포함될 수 있습니다. 예를 들어, printf("Hello, world")문자열 "Hello, world"가 코드 / 텍스트 세그먼트에 생성됩니다. sizeLinux OS에서 명령을 사용하여이를 확인할 수 있습니다 .
  • 추가 자료

데이터 세그먼트

데이터 세그먼트는 아래 두 부분으로 나뉘며 일반적으로 힙 영역 아래 또는 스택 위의 일부 구현에 있지만 데이터 세그먼트는 힙과 스택 영역 사이에 있지 않습니다.

2. 초기화되지 않은 데이터 세그먼트

  • 이 세그먼트는 bss 라고도합니다 .
  • 이것은 다음을 포함하는 메모리 부분입니다.
    1. 초기화되지 않은 전역 변수 (포인터 변수 포함)
    2. 초기화되지 않은 상수 전역 변수 .
    3. 초기화되지 않은 로컬 정적 변수 .
  • 초기화되지 않은 전역 또는 정적 지역 변수는 초기화되지 않은 데이터 세그먼트에 저장됩니다
  • 예를 들어, 글로벌 변수 int globalVar;또는 정적 로컬 변수 static int localStatic;는 초기화되지 않은 데이터 세그먼트에 저장됩니다.
  • 당신이 전역 변수를 선언하고 초기화하는 경우 0또는 NULL다음 여전히 초기화되지 않은 데이터 세그먼트 또는 BSS에 갈 것입니다.
  • 추가 자료

3. 초기화 된 데이터 세그먼트

  • 이 세그먼트는 다음을 저장합니다.
    1. 초기화 된 전역 변수 (포인터 변수 포함)
    2. 초기화 된 상수 전역 변수 .
    3. 로컬 정적 변수를 초기화했습니다 .
  • 예를 들어, 글로벌 변수 int globalVar = 1;또는 정적 로컬 변수 static int localStatic = 1;는 초기화 된 데이터 세그먼트에 저장됩니다.
  • 이 세그먼트는 초기화 된 읽기 전용 영역과 초기화 된 읽기-쓰기 영역 으로 더 분류 될 수있다 . 초기화 된 상수 전역 변수는 초기화 된 읽기 전용 영역으로 이동하고 런타임시 값을 수정할 수있는 변수는 초기화 된 읽기 / 쓰기 영역으로 이동 합니다.
  • 이 세그먼트의 크기는 프로그램 소스 코드의 값 크기에 따라 결정되며 런타임시 변경되지 않습니다 .
  • 추가 자료

4. 스택 세그먼트

  • 스택 세그먼트 (함수 내부에서 생성되는 변수 저장하는 데 사용되는 함수 또는 메인 함수 사용자 정의 함수일 수 ) 변수 등
    1. 함수의 지역 변수 (포인터 변수 포함)
    2. 함수에 전달 된 인수
    3. 반송 주소
  • 스택에 저장된 변수는 함수 실행이 완료되는 즉시 제거됩니다.
  • 추가 자료

5. 힙 세그먼트

  • 이 세그먼트는 동적 메모리 할당을 지원하기위한 것입니다. 프로그래머가 C에서 동적으로 다음 몇 가지 메모리를 할당하고 싶은 경우는 사용하여 수행됩니다 malloc, calloc또는 realloc방법.
  • 예를 들어, int* prt = malloc(sizeof(int) * 2)8 바이트가 힙에 할당되고 해당 위치의 메모리 주소가 반환되어 ptr변수에 저장됩니다 . ptr변수 중 하나가 사용 / 선언되는 방식에 따라 스택이나 데이터 세그먼트에있는 것이다.
  • 추가 자료

초기화되지 않은 데이터 세그먼트에서 초기화되지 않고 초기화되지 않아야합니다.
Suraj Jain

다시 "초기화되지 않은 데이터 세그먼트에 저장" (여러 인스턴스) : 음주 뜻 "데이터 세그먼트에서 초기화되지 않은되어 저장" ?
Peter Mortensen

@PeterMortensen 두 가지를 모두 의미합니다. "초기화되지 않은 모든 글로벌 또는 정적 로컬 변수는 초기화되지 않은 데이터 세그먼트에 저장됩니다"
hagrawal

C에서 전역 정적 변수를 어떻게 가질 수 있습니까?

"일부 헤드 업"에서 "글로벌 정적 또는 로컬 정적 변수를 사용할 수 있지만 위의 세 가지 유형은 상위 유형입니다." 여기서 u는 "전역 정적"이라는 용어를 나타냅니다. 내 요지는 정적 변수가 전역 변수가 될 수 없다는 것입니다. 즉, 변수가 전역 변수 여야하는 경우 프로그램 실행이 완료 될 때까지 변수에 액세스 할 수 있어야합니다. 내가 틀렸다면 설명하고 도와주세요.

11

잘못된 문장을 수정

constant data types ----->  code //wrong

지역 상수 변수 -----> 스택

초기화 된 전역 상수 변수 -----> 데이터 세그먼트

초기화되지 않은 전역 상수 변수 -----> bss

variables declared and defined in main function  ----->  heap //wrong

메인 함수에서 선언되고 정의 된 변수 -----> stack

pointers(ex:char *arr,int *arr) ------->  heap //wrong

dynamically allocated space(using malloc,calloc) --------> stack //wrong

pointers (ex : char * arr, int * arr) -------> 해당 포인터 변수의 크기는 스택에 있습니다.

동적으로 n 바이트의 메모리를 할당 malloc하거나 ( 또는 사용 calloc) 포인터 변수를 가리 키도록 만듭니다. 이제 n메모리 바이트가 힙에 있고 포인터 변수 n는 메모리 청크 바이트의 시작 포인터를 저장하기 위해 스택에있는 4 바이트 (64 비트 시스템 8 바이트 인 경우)를 필요로 합니다.

참고 : 포인터 변수는 모든 세그먼트의 메모리를 가리킬 수 있습니다.

int x = 10;
void func()
{
int a = 0;
int *p = &a: //Now its pointing the memory of stack
int *p2 = &x; //Now its pointing the memory of data segment
chat *name = "ashok" //Now its pointing the constant string literal 
                     //which is actually present in text segment.
char *name2 = malloc(10); //Now its pointing memory in heap
...
}

동적으로 할당 된 공간 (malloc, calloc 사용) --------> 힙


포인터는 스택 또는 힙에있을 수 있습니다 (특히 포인터 참조)
argentage

@airza : 이제 업데이트되었습니다. 실제로 나는 그 세부 사항 만 업데이트하고있었습니다 :)
rashok

다음 메모리 맵에서 스택과 힙이 어디에 있는지 알려 주시겠습니까? 스택과 메모리가 런타임에만 적용 가능하기 때문에 이것이 올바른 질문인지 확실하지 않습니다. 메모리 맵 : "text data bss dec hex filename 7280 1688 1040 10008 2718 a.exe"
Mahori

7

널리 사용되는 데스크탑 아키텍처는 프로세스의 가상 메모리를 여러 세그먼트로 나눕니다 .

  • 텍스트 세그먼트 : 실행 코드가 들어 있습니다. 명령 포인터는이 범위의 값을 갖습니다.

  • 데이터 세그먼트 : 전역 변수 (예 : 정적 링크가있는 객체)를 포함합니다. 읽기 전용 데이터 (예 : 문자열 상수)와 초기화되지 않은 데이터 ( "BSS")로 세분화되었습니다.

  • 스택 세그먼트 : 프로그램 의 동적 메모리, 즉 사용 가능한 저장소 ( "힙") 및 모든 스레드의 로컬 스택 프레임이 포함됩니다. 전통적으로 C 스택과 C 힙은 반대쪽 끝에서 스택 세그먼트로 성장하는 데 사용되었지만 너무 안전하지 않아 연습이 중단되었다고 생각합니다.

AC 프로그램은 일반적으로 정적 저장 기간을 가진 객체를 데이터 세그먼트에, 자유 저장소에 동적으로 할당 된 객체 및 살아있는 스레드의 호출 스택에 자동 객체를 넣습니다.

구형 x86 리얼 모드 또는 임베디드 장치와 같은 다른 플랫폼에서는 상황이 완전히 다를 수 있습니다.


"실습이 너무 안전하지 않기 때문에 연습이 중단되었다고 생각합니다."-스레드를 구현할 수 없게되므로 프로그램 당 하나 이상의 스택이 필요하며 모두 끝날 수는 없습니다
Jess Jessop

@SteveJessop : 예, 저도 그렇게 생각하고있었습니다. 그러나 스레드는 오랫동안 존재했습니다. 모든 스레드 스택이 뒤로 자랐는지 또는 힙처럼 자랐는지 모르겠습니다. 어쨌든 요즘 모든 것이 같은 방향으로 가고 가드가 있습니다. 페이지.
Kerrek SB

6

나는 C 관점에서만 이러한 변수를 언급하고 있습니다.

C 언어 의 관점에서 중요한 것은 범위, 범위, 연결 및 액세스입니다. 항목이 다른 메모리 세그먼트에 정확히 어떻게 매핑되는지는 개별 구현에 달려 있으며 이는 다양합니다. 언어 표준은 메모리 세그먼트 대해 전혀 이야기하지 않습니다 . 대부분의 현대 건축은 대부분 같은 방식으로 작동합니다. 블록 범위 변수 및 함수 인수는 스택에서 할당되고 파일 범위 및 정적 변수는 데이터 또는 코드 세그먼트에서 할당되며 동적 메모리는 힙에서 할당되며 일부 상수 데이터는 읽기 전용 세그먼트에 저장됩니다 등


3

스토리지에 대해 염두에 두어야 할 한 가지는 as-if 규칙 입니다. 컴파일러는 특정 위치에 변수를 배치 할 필요가 없습니다. 대신 컴파일 된 프로그램이 추상 C 시스템의 규칙에 따라 추상 C 시스템에서 실행 되는 것처럼 동작하는 한 원하는 위치에 배치 할 수 있습니다 . 이것은 모든 저장 기간에 적용됩니다 . 예를 들면 다음과 같습니다.

  • 모든 것에 접근 할 수없는 변수는 완전히 제거 될 수 있습니다-그것은 어디에도 저장 공간이 없습니다. - 42생성 된 어셈블리 코드에는 있지만 부호는없는 방법을 참조하십시오 404.
  • 주소가 자동 저장 기간이 아닌 변수는 메모리에 전혀 저장할 필요가 없습니다. 루프 변수가 그 예입니다.
  • 메모리에 const있거나 효과적으로 const메모리에있을 필요가없는 변수 -컴파일러는 그것이 코드에 foo효과적으로 const사용되는 것을 증명할 수 있습니다 . bar외부 링크가 있고 컴파일러는 현재 모듈 외부에서 변경되지 않음을 증명할 수 없으므로 인라인되지 않습니다.
  • 할당 된 객체 malloc는 힙에서 할당 된 메모리에 상주 할 필요가 없습니다! -코드가 어떻게 호출되지 않고 malloc메모리에 값 42가 저장되어 있지 않은지 , 레지스터에 유지됩니다!
  • 따라서 메모리 누출 mallocfree 필요가없는 객체를 할당 해제하지 않고 할당되고 참조가 된 객체는 손실됩니다 ...
  • 에 의해 할당 된 객체 는 Unixen 에서 프로그램 나누기 ( ) 아래malloc힙 내에있을 필요가 없습니다 ...sbrk(0)

1

포인터 (ex : char * arr, int * arr) -------> heap

아니요, 스택이나 데이터 세그먼트에있을 수 있습니다. 그들은 어디든 가리킬 수 있습니다.


main동적으로 할당 된 변수 에 대한 설명 과 잘못된 변수도 잘못되었습니다
simonc

스택 또는 데이터 세그먼트에서만이 아닙니다. 포인터 배열을 가리키는 포인터를 생각하십시오. 이 경우 배열의 포인터는 힙에 저장됩니다.
Sebi2020

1
  • 변수 / 자동 변수 ---> 스택 섹션
  • 동적으로 할당 된 변수 ---> 힙 섹션
  • 초기화 된 전역 변수-> 데이터 섹션
  • 초기화되지 않은 전역 변수-> 데이터 섹션 (bss)
  • 정적 변수-> 데이터 섹션
  • 문자열 상수-> 텍스트 섹션 / 코드 섹션
  • 함수-> 텍스트 섹션 / 코드 섹션
  • 텍스트 코드-> 텍스트 섹션 / 코드 섹션
  • 레지스터-> CPU 레지스터
  • 명령 줄 입력-> 환경 / 명령 줄 섹션
  • 환경 변수-> 환경 / 명령 줄 섹션

환경 / 명령 줄 섹션이란 무엇입니까? 그들은 리눅스에 존재합니까?
Haoyuan Ge

-1

분해 분석이 가능한 Linux 최소 실행 가능 예제

이것은 표준으로 지정되지 않은 구현 세부 사항이므로 컴파일러가 특정 구현에서 수행하는 작업을 살펴 ​​보겠습니다.

이 답변에서는 분석을 수행하는 특정 답변에 연결하거나 여기에 직접 분석을 제공하고 여기에 모든 결과를 요약합니다.

그것들은 모두 다양한 Ubuntu / GCC 버전에 있으며 결과는 버전간에 상당히 안정적 일 수 있지만 변형이 발견되면보다 정확한 버전을 지정하십시오.

함수 내부의 지역 변수

그것이 main아니면 다른 기능이 되십시오 :

void f(void) {
    int my_local_var;
}

에서와 같이 어떤 GDB의 평균 <값은 밖으로 최적화>는 무엇입니까?

  • -O0: 스택
  • -O3: 유출되지 않으면 등록하고, 그렇지 않으면 스택

스택이 존재하는 이유에 대한 동기 부여 는 x86 어셈블리의 레지스터에 사용되는 푸시 / 팝 명령어의 기능은 무엇입니까?를 참조하십시오.

글로벌 변수 및 static함수 변수

/* BSS */
int my_global_implicit;
int my_global_implicit_explicit_0 = 0;

/* DATA */
int my_global_implicit_explicit_1 = 1;

void f(void) {
    /* BSS */
    static int my_static_local_var_implicit;
    static int my_static_local_var_explicit_0 = 0;

    /* DATA */
    static int my_static_local_var_explicit_1 = 1;
}

char *char c[]

: 그림과 같이 C 및 C ++에 저장된 정적 변수?

void f(void) {
    /* RODATA / TEXT */
    char *a = "abc";

    /* Stack. */
    char b[] = "abc";
    char c[] = {'a', 'b', 'c', '\0'};
}

TODO는 매우 큰 문자열 리터럴도 스택에 배치합니까? 아니면 .data? 아니면 컴파일이 실패합니까?

함수 인수

void f(int i, int j);

관련 호출 규칙 (예 : X86의 경우 https://en.wikipedia.org/wiki/X86_calling_conventions) 을 따라야합니다. X86의 경우 각 변수의 특정 레지스터 또는 스택 위치를 지정합니다.

그런 다음 gdb에서 <값 최적화 됨>의 의미는 무엇입니까? , -O0동안 다음, 스택에 모든 것을 slurps -O3시도는 가능한 한 레지스터를 사용합니다.

그러나 함수가 인라인되면 일반 지역처럼 취급됩니다.

const

나는 당신이 그것을 캐스트 할 수 있기 때문에 아무런 차이가 없다고 생각합니다.

반대로, 컴파일러가 일부 데이터가 쓰여지지 않은 것으로 판단 할 수 .rodata있다면 const가 아닌 경우에도 이론상으로 데이터를 배치 할 수 있습니다.

TODO 분석.

포인터

그것들은 변수 (주소를 포함하고 숫자입니다), 나머지와 동일합니다 :-)

Malloc

문제는 훨씬 이해가되지 않습니다 malloc때문에, malloc기능, 그리고 지역 :

int *i = malloc(sizeof(int));

*i 는 주소를 포함하는 변수이므로 위의 경우에 해당합니다.

malloc이 내부적으로 작동하는 방식에 관해서는 Linux 커널을 호출 할 때 내부 데이터 구조에서 특정 주소를 쓰기 가능으로 표시하고 처음에 프로그램에 의해 만지면 오류가 발생하고 커널은 페이지 테이블을 활성화하여 액세스 할 수 있습니다 segfaul없이 발생 : x86 페이징은 어떻게 작동합니까?

그러나 이것은 기본적으로 exec실행 파일을 실행하려고 할 때 syscall이 후드에서 수행하는 것과 정확히 일치 합니다.로드하려는 페이지를 표시하고 거기에 프로그램을 작성합니다. 또한 다음을 참조하십시오. 커널에서 실행 가능한 이진 파일을 실행하는 방법 리눅스? exec그것을로드 할 위치에 대한 추가 제한이 있습니다 (예 : 코드 를 재배치 할 수없는 경우 제외 ).

에 사용되는 정확한 콜이 malloc입니다 mmap현대 2020 구현에서, 과거에 brk사용되었습니다 합니까 용의 malloc ()을 사용 BRK () 또는 mmap를 ()?

동적 라이브러리

기본적으로 mmap메모리에 액세스하십시오 : /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710

envinroment 변수와 mainargv

초기 스택 위 : /unix/75939/where-is-the-environment-string-actual-stored TODO 왜 .data에 있지 않습니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.