C에서 괄호는 스택 프레임 역할을합니까?
새 중괄호 세트 내에 변수를 작성하면 해당 변수가 닫는 중괄호의 스택에서 튀어 나왔습니까? 아니면 함수가 끝날 때까지 행 아웃됩니까? 예를 들면 다음과 같습니다.
void foo() {
int c[100];
{
int d[200];
}
//code that takes a while
return;
}
윌 d
동안 메모리를 복용 할 code that takes a while
부분?
아니요, 괄호는 스택 프레임으로 작동하지 않습니다. C에서 중괄호는 명명 범위 만 나타내지 만, 제어가 통과 할 때 아무것도 파괴되거나 스택에서 튀어 나오는 것이 없습니다.
프로그래머가 코드를 작성하면 종종 스택 프레임 인 것처럼 생각할 수 있습니다. 중괄호 안에 선언 된 식별자는 중괄호 내에서만 액세스 할 수 있으므로 프로그래머의 관점에서 볼 때 범위가 종료 될 때 스택에 푸시되고 튀어 나오는 것과 같습니다. 그러나 컴파일러는 진입 / 종료시 어떤 것도 푸시 / 팝핑하는 코드를 생성 할 필요가 없으며 일반적으로 그렇지 않습니다.
또한 지역 변수는 스택 공간을 전혀 사용하지 않을 수 있습니다. CPU 레지스터 나 다른 보조 기억 장치 위치에 유지되거나 완전히 최적화 될 수 있습니다.
따라서 d
이론적으로 배열은 전체 기능을 위해 메모리를 소비 할 수 있습니다. 그러나 컴파일러는이를 최적화하거나 사용 수명이 겹치지 않는 다른 로컬 변수와 메모리를 공유 할 수 있습니다.
변수가 실제로 메모리를 차지하는 시간 은 분명히 컴파일러에 따라 다릅니다 (그리고 많은 컴파일러는 내부 블록이 함수 내에서 들어오고 나올 때 스택 포인터를 조정하지 않습니다).
그러나 밀접하게 관련되어 있지만 더 흥미로운 질문은 프로그램이 내부 범위 외부 (그러나 포함 함수 내)의 내부 객체에 액세스 할 수 있는지 여부입니다.
void foo() {
int c[100];
int *p;
{
int d[200];
p = d;
}
/* Can I access p[0] here? */
return;
}
(즉 , 실제로는 그렇지 않은 경우에도 컴파일러 가 할당을 해제 할 수d
있습니까?).
대답은 컴파일러 가 할당 해제 할 수 있고 주석이 나타내는 위치에 d
액세스 p[0]
하는 것이 정의되지 않은 동작이라는 것입니다 (프로그램은 내부 범위 외부의 내부 객체에 액세스 할 수 없음 ). C 표준의 관련 부분은 6.2.4p5입니다.
가변 길이 배열 유형이없는 객체 (자동 저장 기간이있는 객체) 의 경우 수명은 해당 블록의 실행이 어떤 식 으로든 끝날 때까지 연관된 블록으로 시작됩니다 . (동봉 된 블록을 입력하거나 함수를 호출하면 현재 블록의 실행이 일시 중단되지만 종료되지는 않습니다.) 블록이 재귀 적으로 입력되면 매번 객체의 새 인스턴스가 생성됩니다. 개체의 초기 값은 불확실합니다. 객체에 대해 초기화가 지정되면 블록 실행시 선언에 도달 할 때마다 수행됩니다. 그렇지 않으면 선언에 도달 할 때마다 값이 결정되지 않습니다.
귀하의 질문은 명확하게 답변 될만큼 명확하지 않습니다.
한편으로, 컴파일러는 일반적으로 중첩 된 블록 범위에 대해 로컬 메모리 할당 할당 해제를 수행하지 않습니다. 로컬 메모리는 일반적으로 기능 입력시 한 번만 할당되고 기능 종료시 해제됩니다.
반면, 로컬 객체의 수명이 끝나면 해당 객체가 차지하는 메모리를 나중에 다른 로컬 객체에 재사용 할 수 있습니다. 예를 들어이 코드에서
void foo()
{
{
int d[100];
}
{
double e[20];
}
}
두 어레이는 일반적으로 동일한 메모리 영역을 차지하므로 기능에 필요한 로컬 스토리지의 총량 은 두 어레이 중 가장 큰 어레이에 필요한 양이며 동시에 두 어레이에 foo
필요한 것은 아닙니다.
후자 d
가 질문의 맥락에서 기능이 끝날 때까지 메모리 를 계속 차지 하는지 자격이 있는지 여부는 결정하는 것입니다.
It's implementation dependent. I wrote a short program to test what gcc 4.3.4 does, and it allocates all of the stack space at once at the start of the function. You can examine the assembly that gcc produces using the -S flag.
No, d[] will not be on the stack for the remainder of routine. But alloca() is different.
Edit: Kristopher Johnson (and simon and Daniel) are right, and my initial response was wrong. With gcc 4.3.4.on CYGWIN, the code:
void foo(int[]);
void bar(void);
void foobar(int);
void foobar(int flag) {
if (flag) {
int big[100000000];
foo(big);
}
bar();
}
gives:
_foobar:
pushl %ebp
movl %esp, %ebp
movl $400000008, %eax
call __alloca
cmpl $0, 8(%ebp)
je L2
leal -400000000(%ebp), %eax
movl %eax, (%esp)
call _foo
L2:
call _bar
leave
ret
Live and learn! And a quick test seems to show that AndreyT is also correct about multiple allocations.
Added much later: The above test shows the gcc documentation is not quite right. For years it has said (emphasis added):
"The space for a variable-length array is deallocated as soon as the array name's scope ends."
They might. They might not. The answer I think you really need is: Don't ever assume anything. Modern compilers do all kinds of architecture and implementation-specific magic. Write your code simply and legibly to humans and let the compiler do the good stuff. If you try to code around the compiler you're asking for trouble - and the trouble you usually get in these situations is usually horribly subtle and difficult to diagnose.
Your variable d
is typically not popped off the stack. Curly braces do not denote a stack frame. Otherwise, you would not be able to do something like this:
char var = getch();
{
char next_var = var + 1;
use_variable(next_char);
}
If curly braces caused a true stack push/pop (like a function call would), then the above code would not compile because the code inside the braces would not be able to access the variable var
that lives outside the braces (just like a sub-function cannot directly access variables in the calling function). We know that this is not the case.
Curly braces are simply used for scoping. The compiler will treat any access to the "inner" variable from outside the enclosing braces as invalid, and it may re-use that memory for something else (this is implementation-dependent). However, it may not be popped off of the stack until the enclosing function returns.
Update: Here's what the C spec has to say. Regarding objects with automatic storage duration (section 6.4.2):
For an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in anyway.
The same section defines the term "lifetime" as (emphasis mine):
The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime. If an object is referred to outside of its lifetime, the behavior is undefined.
The key word here is, of course, 'guaranteed'. Once you leave the scope of the inner set of braces, the array's lifetime is over. Storage may or may not still be allocated for it (your compiler might re-use the space for something else), but any attempts to access the array invoke undefined behavior and bring about unpredictable results.
The C spec has no notion of stack frames. It speaks only to how the resulting program will behave, and leaves the implementation details to the compiler (after all, the implementation would look quite different on a stackless CPU than it would on a CPU with a hardware stack). There is nothing in the C spec that mandates where a stack frame will or will not end. The only real way to know is to compile the code on your particular compiler/platform and examine the resulting assembly. Your compiler's current set of optimization options will likely play a role in this as well.
If you want to ensure that the array d
is no longer eating up memory while your code is running, you can either convert the code in curly braces into a separate function or explicitly malloc
and free
the memory instead of using automatic storage.
I believe that it does go out of scope, but is not pop-ed off the stack until the function returns. So it will still be taking up memory on the stack until the function is completed, but not accessible downstream of the first closing curly brace.
There has already been given much information on the standard indicating that it is indeed implementation specific.
So, one experiment might be of interest. If we try the following code:
#include <stdio.h>
int main() {
int* x;
int* y;
{
int a;
x = &a;
printf("%p\n", (void*) x);
}
{
int b;
y = &b;
printf("%p\n", (void*) y);
}
}
Using gcc we obtain here two times the same address: Coliro
But if we try the following code:
#include <stdio.h>
int main() {
int* x;
int* y;
{
int a;
x = &a;
}
{
int b;
y = &b;
}
printf("%p\n", (void*) x);
printf("%p\n", (void*) y);
}
Using gcc we obtain here two different addresses: Coliro
So, you can't be really sure what is going on.
참고URL : https://stackoverflow.com/questions/2759371/in-c-do-braces-act-as-a-stack-frame
'Programing' 카테고리의 다른 글
공개 친구 교환 회원 기능 (0) | 2020.06.10 |
---|---|
해당 행이나 열에 0이 포함되어 있으면 행렬의 모든 셀을 0으로 설정하십시오. (0) | 2020.06.09 |
mavn에서 mvn가 정확히 무엇을 설치합니까? (0) | 2020.06.09 |
invokedynamic이란 무엇이며 어떻게 사용합니까? (0) | 2020.06.09 |
css 파일을 안에 넣는 경우 차이점은 무엇입니까? (0) | 2020.06.09 |