2010-04-19 3 views
7

그래서 libc의 stdio 부분이 어떻게 구현되는지 파헤쳐 봤고 또 다른 질문을 발견했습니다. I는 다음에 볼 man setvbuf 상대 :누가 무료로 setvbuf 버퍼를 사용합니까?

제 I/O 동작에 파일을 발생의 malloc (3)라고하고, 버퍼가 얻어진다.

사용자가 실제로 사용하지 않으면 프로그램에 I/O 용으로 malloc이 없어야합니다. 내 직감에 대한 반응은 libc가 여기에 자신의 혼란을 치울 것입니다. valgrind가 메모리 누수를보고하지 않기 때문에 나는 그럴 수 있다고 가정 할 수 있습니다. 그들은 물론 더러운 것을 수행하고 malloc을 통해 직접 할당하지 않을 수 있습니다. 그러나 문자 그대로는 malloc을 사용한다고 가정합니다.)

그러나, 당신은 ... 너무

int main() { 
    char *p = malloc(100); 
    setvbuf(stdio, p, _IOFBF, 100); 
    puts("hello world"); 
} 

오, 아니, 메모리 누수가 자신의 버퍼를 지정할 수 있습니다! valgrind가 그것을 확인합니다. 그래서 stdio가 버퍼를 할당 할 때마다 자동으로 삭제 될 것입니다 (늦어도 프로그램 종료시에, 아마도 스트림 닫기에있을 것입니다). 하지만 버퍼를 명시 적으로 지정하면 직접 버퍼를 정리해야합니다.

캐치가 있습니다. BUF 포인트는 여전히 시간 스트림에 의해 존재하는 그 공간 또한 프로그램 종료에 을 발생하는 닫혀 있는지

당신은 확인해야합니다 : 남자 페이지에는이 말했다. 예를 들어, 다음은 올바르지 않습니다.

이제 표준 스트림에 대해 흥미롭게 보입니다. 프로그램 종료시 닫혀 있기 때문에 수동으로 할당 된 버퍼를 어떻게 적절하게 정리합니까? 나는 파일 구조체 내부에 "나는 플래그를 닫을 때이 정리"상상할 수있는,하지만 난 이런 식으로 뭔가를하고이 권리를 읽으면 때문에 털이 얻을 :

setvbuf(stdout, 0, _IOFBF, 0); 
printf("hello "); 
setvbuf(stdout, 0, _IOLBF, 0); 
printf("world\n"); 

표준 라이브러리에 의해 2 개 할당을 야기의 때문에 이 문장 :

인수 buf가 NULL이면, 모드 만 영향을받습니다. 새 버퍼는 이 다음 읽기 또는 쓰기 작업에 할당되고 작업을 수행합니다.

편집 : 내 질문에 대한 추가 정보. 내가 실제로 에 그것을 사용한다면 freesetvbuf으로 전달하는 모든 버퍼가 free에 전달해야한다는 것이 분명하기 때문에? 프로그램 끝까지 살아 있어야합니다. 내가 생각할 수있는 가장 좋은 방법은 fclose(stdout)입니다. 그런 다음 사람들을 언급 한 것처럼 정적 버퍼를 사용하거나 해제하십시오. 그것이 어색한 디자인 결정처럼 보이기 때문에 나는 묻는다.(적어도 내 시스템에서) man page에서 또한

답변

3

:

BUF가 NULL이 아닌 경우,이 스트림을 닫은 후 무료 (3) 현재의 버퍼에 발신자의 책임입니다.

즉, malloc-ed 그것을 해제하면됩니다.

종료하기 전에 스트림을 직접 닫아 버퍼를 비울 수 있습니다. 또는 스트림을 플러시하고 setvbufNULL 버퍼 인수로 다시 호출하여 라이브러리 관리 버퍼 또는 버퍼링되지 않은 I/O로 다시 전환 할 수 있습니다.

+0

페이지에 대한 링크 된 답변이 업데이트되었습니다. OS X이지만, 맨 페이지는 FreeBSD (http://www.freebsd.org/cgi/man.cgi?query=setvbuf)에서 제공됩니다. – outis

+0

free()로 free'd해서는 안되는 정적 버퍼를 제공 할 수 있기 때문에 상황이 어떻게 될지 알기가 어렵습니다. –

+0

@ Neeil : 실제로 stdlib이 스트림에서 할당 한 버퍼를 얻을 수있는 방법이 없으므로 stdlib에 메모리 누수가 있는지 궁금합니다. –

1

stdin, stdoutstderr을 명시 적으로 닫을 수 있습니다 (fclose()).

대부분의 운영 체제에서 힙 메모리는 프로그램 종료시 자동으로 해제됩니다. 따라서 출시되지 않은 버퍼가있는 실제적인 문제는 없습니다 (미발표 버퍼가 Valgrind의 출력을 오염시키는 것은 표면적 인 문제입니다). setvbuf()을 표준 입력 또는 출력으로 호출하는 충동을 느끼면 정적 버퍼를 사용하는 것이 좋습니다. 정적 버퍼는 할당되거나 해제 될 필요가 없으며 표준 스트림이 세 개 뿐이므로 스트림이 프로그램 종료까지 계속 열려있는 상황에 대해 걱정할 필요가 있으므로 여기서는 적절합니다.

+0

폴링 된 디버깅 출력은 문제가됩니다. 왜냐하면 출력 위에 윤곽을 그리는 습관이 생기고 실제 오류를 쉽게 놓칠 수 있기 때문입니다. –

+0

@ 토마스 : 메모리가 해제되기 전에 파일이 폐쇄된다는 보장이 있습니까? – outis

+0

@outis : 메모리가 자동으로 해제되는 운영 체제에서는 실행 스레드가 존재하지 않는 지점에서 "원자 적"으로 릴리스됩니다. 그 이후에 실행될 수있는 것은 없으며 특히 릴리스 된 버퍼에 (잘못) 액세스 할 수있는 libc 코드가 없습니다. 간단히 말해서 "그냥 효과가있다". 열려있는 파일과 버퍼링 된 데이터가있을 수 있지만, OS 커널 내에서 응용 코드의 범위를 벗어납니다. –

3

적어도 C 표준에 따르면 마지막 시나리오는 단순히 허용되지 않습니다. "setvbuf 함수는 스트림이 가리키는 스트림이 열린 파일과 연결되어 있고 다른 작업 (다른 setvbuf에 대한 실패한 호출보다) 스트림에서 수행됩니다. " (C99, §7.19.5.6/2).

단순한 경우에 메모리를 해제해야하는 시점에 atexit()을 호출하여 main()에서 종료 한 후 메모리가 해제 될 콜백을 등록해야하지만 제어가 OS로 반환되기 전에 호출해야합니다.

+0

흥미 롭습니다. 마지막 예제는 정의되지 않은 동작 범주에 속합니다. –