C의 스택 변수 자동 해제
안타깝게도 C에는 똑똑한 포인터가 없습니다.그러나 변수 선언을 랩핑하고 변수가 선언된 범위를 떠날 때 해당 변수를 입력 변수로 함수 호출을 호출하는 매크로를 구축할 수 있습니까?
긴 문구로 죄송합니다만 참조 카운터가 내장된 많은 요소가 있는 xnu 커널에서 작업하고 있으며, 메모리 누수를 방지하기 위해 이 요소를 사용한 후 이 요소를 해제하는 것을 잊지 말아야 합니다.
예를 들어, 만약 내가 다음과 같은 유형을 가지고 있다면,proc_t
:
struct proc;
typedef struct proc * proc_t;
범위 내에서 이 유형을 기준으로 스택 변수를 선언합니다. 예를 들어:
{
proc_t_release_upon_exit proc_t proc_iter = proc_find(mypid);
//the rest of the code in this scope
}
전처리기가 매크로를 분석한 후 컴파일하기 전에 다음 코드가 생성될 것으로 예상됩니다.
{
proc_t myproc = proc_find(mypid)
//the rest of the code in scope
proc_rele(myproc);
}
C와 같은 매크로를 정의할 수 있는 방법이 있습니까?
GCC에서 Cleanup variable 속성을 사용할 수 있습니다.이것을 보세요: http://echorand.me/site/notes/articles/c_cleanup/cleanup_attribute_c.html
샘플 코드:
#include <stdio.h>
#include <stdlib.h>
void free_memory(void **ptr)
{
printf("Free memory: %p\n", *ptr);
free(*ptr);
}
int main(void)
{
// Define variable and allocate 1 byte, the memory will be free at
// the end of the scope by the free_memory function. The free_memory
// function will get the pointer to the variable *ptr (double pointer
// **ptr).
void *ptr __attribute__ ((__cleanup__(free_memory))) = malloc(1);
return 0;
}
소스 코드를 main.c라는 이름의 파일에 저장하면 다음 명령으로 컴파일할 수 있습니다.
gcc main.c -o main
메모리 누수가 있는지 확인합니다.
valgrind ./main
valgrind에서의 출력 예제:
==1026== Memcheck, a memory error detector
==1026== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1026== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==1026== Command: ./main
==1026==
Free memory: 0x51ff040
==1026==
==1026== HEAP SUMMARY:
==1026== in use at exit: 0 bytes in 0 blocks
==1026== total heap usage: 1 allocs, 1 frees, 1 bytes allocated
==1026==
==1026== All heap blocks were freed -- no leaks are possible
==1026==
==1026== For counts of detected and suppressed errors, rerun with: -v
==1026== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
C는 먼저 실행될 다른 코드보다 구문적으로 코드를 먼저 배치하는 방법을 제공합니다.for
블록. a의 3항을 기억하세요.for
structure는 임의의 식을 포함할 수 있으며, 주 블록을 실행한 후 항상 실행됩니다.
따라서 다음 코드의 주어진 청크 후에 미리 결정된 호출을 하는 매크로를 만들 수 있습니다.for
매크로의 블럭:
#define M_GEN_DONE_FLAG() _done_ ## __LINE__
#define M_AROUND_BLOCK2(FLAG, DECL, BEFORE, AFTER) \
for (int FLAG = (BEFORE, 0); !FLAG; ) \
for (DECL; !FLAG; FLAG = (AFTER, 1))
#define M_AROUND_BLOCK(DECL, BEFORE, AFTER) M_AROUND_BLOCK2(M_GEN_DONE_FLAG(), DECL, BEFORE, AFTER)
#define M_CLEANUP_VAR(DECL, CLEANUP_CALL) M_AROUND_BLOCK(DECL, (void)0, CLEANUP_CALL)
...이렇게 사용할 수 있습니다.
#include <stdio.h>
struct proc;
typedef struct proc * proc_t;
proc_t proc_find(int);
void proc_rele(proc_t);
void fun(int mypid) {
M_CLEANUP_VAR (proc_t myproc = proc_find(mypid), proc_rele(myproc))
{
printf("%p\n", &myproc); // just to prove it's in scope
}
}
여기서의 비결은.for
블록은 다음 문장을 받아들이지만 실제로 매크로 정의에 이 문장을 넣지 않으면 일반 코드 블록으로 매크로 호출을 수행할 수 있으며 확장된 문장을 따르는 것만으로 새로운 범위-제어-구조 구문에 "마법적으로" 속하게 됩니다.for
.
사용 가치가 있는 옵티마이저는 가장 낮은 최적화 설정에서 루프 플래그를 제거합니다.이름이 깃발과 충돌하는 것은 큰 걱정이 아니라는 것을 유의하십시오(즉, 당신은 정말로 필요하지 않습니다).gensym
이 경우) 플래그는 루프 본체의 범위를 가지며, 중첩 루프는 동일한 플래그 이름을 사용하는 경우 안전하게 숨길 수 있기 때문입니다.
여기서 이점은 정리할 변수의 범위가 제한되고(해당 선언 직후에 화합물 외부에서 사용할 수 없음) 시각적으로 명확하다는 것입니다(해당 화합물 때문에).
장점:
- 이것은 확장이 없는 표준 C입니다.
- 제어 흐름이 간단합니다.
- () ()합니다.
__attribute__ __cleanup__
단점:
- "" RAI 를(, )로부터 ).
goto
는 C++외:__cleanup__
일반적으로 후드 아래에 C++ 기계로 구현되므로 더욱 완성도가 높습니다.)더 것은 은인입니다를 것입니다.return
(고맙습니다 @Voo.)(적어도 위치가 잘못되지 않도록 보호할 수 있습니다.break
- 만약 당신이 원한다면 - 세번째 줄을 추가함으로써,switch (0) default:
M_AROUND_BLOCK2
.) - 모든 사람이 구문 확장 매크로에 동의하는 것은 아닙니다. (그러나 여기서 C의 의미론을 확장하는 것을 고려하면...)
당신이 듣고 싶어 하는 말이 아니라는 것을 알지만, 나는 당신이 이것을 하지 않기를 권합니다.
모든 것이 정리되기 전에 단일 반환점을 갖는 것은 완벽하게 허용되는 C 스타일입니다.예외가 없기 때문에 이것은 하기 쉽고, 기능을 보고 확인하기 쉽습니다.
이 작업을 위해 매크로 해커리 또는 컴파일러 "기능"을 사용하는 것은 C 스타일로 허용되지 않습니다.당신이 읽고 이해하는 것은 모든 사람들에게 부담이 될 것입니다.그리고 결국에는 큰 이득을 얻지 못합니다.
언급URL : https://stackoverflow.com/questions/44819409/auto-release-of-stack-variables-in-c
'programing' 카테고리의 다른 글
MySQL의 조건부 업데이트 (0) | 2023.10.10 |
---|---|
ng급과 ng급의 차이점은 무엇입니까? (0) | 2023.10.10 |
adb 내 장치/폰을 찾지 못함(MacOS X) (0) | 2023.10.05 |
Oracle plsql 블록에 삽입된 총 행 수를 세는 방법 (0) | 2023.10.05 |
woo commerce 신규 사용자 이메일 (0) | 2023.10.05 |