fread는 실제로 어떻게 작동합니까?
의 선언은 fread
다음과 같습니다.
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
질문 : 두 개의 같은 통화의 판독 성능에 차이가 있습니다 fread
:
char a[1000];
fread(a, 1, 1000, stdin);
fread(a, 1000, 1, stdin);
매번 한 번에1000
바이트 를 읽 습니까?
성능에는 차이가있을 수도 있고 없을 수도 있습니다. 의미 체계에 차이가 있습니다.
fread(a, 1, 1000, stdin);
각각 길이가 1 바이트 인 1000 개의 데이터 요소를 읽으려고 시도합니다.
fread(a, 1000, 1, stdin);
1000 바이트 길이의 데이터 요소 1 개 읽기를 시도합니다.
fread()
바이트 수가 아니라 읽을 수있는 데이터 요소의 수를 반환 하기 때문에 다릅니다 . 전체 1000 바이트를 읽기 전에 파일 끝 (또는 오류 조건)에 도달하면 첫 번째 버전은 읽은 바이트 수를 정확히 표시해야합니다. 두 번째는 실패하고 0을 반환합니다.
실제로는 1000 바이트 읽기를 시도하고 실제로 읽은 바이트 수를 나타내는 하위 수준 함수를 호출 할 것입니다. 더 큰 읽기의 경우 여러 하위 수준 호출을 만들 수 있습니다. 반환되는 값의 계산 fread()
은 다르지만 계산 비용은 사소합니다.
구현시 데이터 읽기를 시도하기 전에 읽을 데이터가 충분하지 않다는 것을 알 수 있다면 차이가있을 수 있습니다. 예를 들어, 900 바이트 파일에서 읽는 경우 첫 번째 버전은 900 바이트를 모두 읽고 900을 반환하는 반면 두 번째 버전은 아무것도 읽지 않을 수 있습니다. 두 경우 모두 파일 위치 표시기는 성공적으로 읽은 문자 수 ( 예 : 900) 만큼 앞당겨집니다 .
그러나 일반적으로 필요한 정보에 따라 호출 방법을 선택해야합니다. 부분 읽기가 아무것도 읽지 않는 것보다 낫지 않으면 단일 데이터 요소를 읽습니다. 부분 읽기가 유용한 경우 더 작은 청크로 읽습니다.
따르면 명세서 두 구현은 다르게 처리 될 수있다.
파일이 1000 바이트 미만인 경우 fread(a, 1, 1000, stdin)
(각각 1 바이트 씩 1000 개 요소 읽기) EOF까지 모든 바이트를 복사합니다. 반면에 fread(a, 1000, 1, stdin)
(1 개의 1000 바이트 요소 읽기)에 저장된 결과 a
는 '첫 번째'(및 유일한) 1000 바이트 요소 읽기를 완료 할 데이터가 충분하지 않기 때문에 지정되지 않습니다.
물론 일부 구현에서는 여전히 'partial'요소를 필요한만큼의 바이트로 복사 할 수 있습니다.
이것이 구현 세부 사항입니다. glibc에서는 기본적으로 (Ref http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iofread.c ) 로 구현 되었기 때문에 성능면에서 동일합니다 .
size_t fread (void* buf, size_t size, size_t count, FILE* f)
{
size_t bytes_requested = size * count;
size_t bytes_read = read(f->fd, buf, bytes_requested);
return bytes_read / size;
}
C 및 POSIX표준은 size
항상 크기의 전체 개체를 읽어야 한다고 보장하지 않습니다 . 완전한 객체를 읽을 수없는 경우 (예 : stdin
999 바이트 만 있지만 요청한 경우 size == 1000
) 파일은 중간 상태 (C99 §7.19.8.1 / 2)로 유지됩니다.
편집 : POSIX에 대한 다른 답변을 참조하십시오.
성능 차이는 없을 수 있지만 이러한 호출은 동일하지 않습니다.
fread
읽은 요소의 수를 반환하므로 이러한 호출은 다른 값을 반환합니다.- 요소를 완전히 읽을 수없는 경우 해당 값은 불확실합니다.
오류가 발생하면 스트림에 대한 파일 위치 표시기의 결과 값이 불확실합니다. 부분 요소를 읽으면 그 값은 불확실합니다. (ISO / IEC 9899 : TC2 7.19.8.1)
읽을 바이트 수를 결정하기 위해 요소 크기에 요소 수를 곱하고 마지막에 읽은 양을 멤버 크기로 나누는 glibc 구현 에는 큰 차이가 없습니다 . 그러나 요소 크기를 1로 지정하는 버전은 항상 읽은 올바른 바이트 수를 알려줍니다. 그러나 특정 크기의 완전히 읽는 요소에만 관심이있는 경우 다른 형식을 사용하면 분할을 수행하지 않아도됩니다.
fread
getc
내부적으로 호출합니다 . 의 Minix
횟수 getc
라고 단순히 size*nmemb
그렇게 몇 번 getc
호출 될에 따라 제품 이 두 가지의. 두 그래서 fread(a, 1, 1000, stdin)
및 fread(a, 1000, 1, stdin)
실행 getc
1000=(1000*1)
시간을. 다음은 fread
Minix 의 간단한 구현입니다.
size_t fread(void *ptr, size_t size, size_t nmemb, register FILE *stream){
register char *cp = ptr;
register int c;
size_t ndone = 0;
register size_t s;
if (size)
while ( ndone < nmemb ) {
s = size;
do {
if ((c = getc(stream)) != EOF)
*cp++ = c;
else
return ndone;
} while (--s);
ndone++;
}
return ndone;
}
http://pubs.opengroup.org/onlinepubs/000095399/functions/fread.html 한 가지 더 문장 형식 이 주목할 만합니다.
fread () 함수는 stream이 가리키는 스트림에서 크기가 바이트 단위로 지정된 nitems 요소까지 ptr이 가리키는 배열을 읽어야합니다. 각 객체에 대해 크기 호출이 fgetc () 함수에 수행되고 결과 는 객체를 정확히 오버레이하는 부호없는 문자 배열에 읽은 순서대로 저장됩니다 .
Inshort in both case data will be accessed by fgetc()...!
I wanted to clarify the answers here. fread performs buffered IO. The actual read block sizes fread uses are determined by the C implementation being used.
All modern C libraries will have the same performance with the two calls:
fread(a, 1, 1000, file);
fread(a, 1000, 1, file);
Even something like:
for (int i=0; i<1000; i++)
a[i] = fgetc(file)
Should result in the same disk access patterns, although fgetc would be slower due to more calls into the standard c libraries and in some cases the need for a disk to perform additional seeks which would have otherwise been optimized away.
Getting back to the difference between the two forms of fread. The former returns the actual number of bytes read. The latter returns 0 if the file size is less than 1000, otherwise it returns 1. In both cases the buffer would be filled with the same data, i.e. the contents of the file up to 1000 bytes.
In general, you probably want to keep the 2nd parameter (size) set to 1 such that you get the number of bytes read.
참고URL : https://stackoverflow.com/questions/8589425/how-does-fread-really-work
'Program Tip' 카테고리의 다른 글
apt 저장소를 신뢰하는 방법 : Debian apt-get 업데이트 오류 공개 키를 사용할 수 없습니다 : NO_PUBKEY (0) | 2020.10.29 |
---|---|
인스턴스 이니셜 라이저는 생성자와 어떻게 다릅니 까? (0) | 2020.10.29 |
SQL을 사용하여 날짜 필드에서 월별로 그룹화하는 방법 (0) | 2020.10.29 |
localhost URL에 하위 도메인 추가 (0) | 2020.10.29 |
인수에 대한 밑줄이있는 Python의 람다? (0) | 2020.10.29 |