제가 몇 년 전에 외국 사이트에서 CRC32 계산 코드를 구했는데, 실제 쓰려고 보니까 실용성에 문제가 있었습니다. 파일을 메모리에 모두 읽어들인 후에 계산하는 것이었습니다. 그래서 만약 700메가짜리 CD 이미지 파일의 CRC32를 구하려면 메모리가 700메가나 필요했습니다.
그래서 메모리에 로딩하지 않고 파일을 조금 조금씩 읽어서 계산하도록 만든 것이 아래에 소개하는 코드입니다. 버퍼로서 불과 32768 바이트만 필요합니다. 사실상 메모리를 전혀 요구하지 않는 것입니다. (삼성 이건희 회장의 얼굴이 파랗게 질릴 수도 있겠군요^^)
속도
어셈블리로 만들어진 CRC32 계산 프로그램의 속도와 같았습니다.
비주얼C/C++가 그만큼 최적화를 잘 해준다는 의미일 것입니다.
호환성
ZIP 과 RAR 의 CRC32 계산 값과 동일합니다.
사용법
컴파일하면 getCRC.exe 라는 파일이 만들어집니다. 명령 프롬프트 창에서,
getCRC <파일 이름>
이런 형식으로 사용하시면 됩니다.
파일 이름에 공백이 들어 있다면 쌍따옴표로 둘러싸 주어야 합니다. 그렇지 않으면 파일을 찾지 못하고 에러(Cannot open input file)를 출력합니다:
D:\Z>getcrc "Merriam-Webster Collegiate's Dictionary.iso"
A745B2FE: Merriam-Webster Collegiate's Dictionary.iso
D:\Z>getcrc Merriam-Webster Collegiate's Dictionary.iso
Cannot open input file.
D:\Z>
다음의 소스 파일 2개를
getCRC.cpp // 프로그램 본체
CRC32.cpp // CRC32 알고리즘 라이브러리
같은 디렉토리에 넣고
cl getCRC.cpp
이런 명령으로 컴파일하면 됩니다.
다음 창은 cl getCRC.cpp 로 컴파일함과 동시에, 컴파일된 파일에 옵션을 주어 한꺼번에 실행시키는 장면입니다.
D:\Z>cl getCRC.cpp && getCRC 0.htm
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
getCRC.cpp
Microsoft (R) Incremental Linker Version 7.10.3077
Copyright (C) Microsoft Corporation. All rights reserved.
/out:getCRC.exe
getCRC.obj
24531DE5: 0.htm
D:\Z>
0.htm 이라는 파일의 CRC32 값인 24531DE5 가 즉시 계산되었습니다.
소스 코드: getCRC.cpp
※ 아래 박스 클릭 후, 키보드 화살표 키로 좌우 스크롤 가능함
#include <stdio.h>
#include <stdlib.h>
#include "CRC32.cpp"
void help(void);
void error(int);
int main(int argc, char *argv[]) {
FILE *in;
if (argc == 1) help();
if( (in = fopen(argv[1], "rb")) == NULL) error(1);
printf("%08lX: %s\n", getFileCRC(in), argv[1]);
fcloseall();
return 0;
}
void help(void) {
printf("\n\tGet the CRC32 of a given file\n\n\tUsage: this_program_name <file_name>\n");
exit(1);
}
void error(int number) {
switch (number) {
case 1 : fputs("Cannot open input file.\n", stderr); break;
}
exit(number);
}
소스 코드: CRC32.cpp
업데이트(Update): 마조리카님께서 지적해 주신대로, 코드의 불합리한 부분을 제거하고 최적화시켰습니다: (New Version) ▶▶ C언어] CRC32 구하기 버전업 (코드 최적화): CRC32.cpp
(Old Version:) # 이것은 최적화가 안 된 구버전이니, 위의 주소의 새 버전을 사용하세요.
unsigned long getFileCRC(FILE *);
unsigned long calcCRC (const unsigned char *, signed long, unsigned long);
void makeCRCtable(unsigned long *, unsigned long);
unsigned long getFileCRC(FILE *s) {
unsigned char buf [32768];
unsigned long CRC = 0;
size_t len;
while ( (len = fread(buf, 1, sizeof(buf), s)) != NULL )
CRC = calcCRC(buf, (unsigned long) len, CRC);
return CRC;
}
unsigned long calcCRC(const unsigned char *mem, signed long size, unsigned long CRC) {
unsigned long table[256];
CRC = ~CRC;
makeCRCtable(table, 0xEDB88320);
while(size--)
CRC = table[(CRC ^ *(mem++)) & 0xFF] ^ (CRC >> 8);
return ~CRC;
}
void makeCRCtable(unsigned long *table, unsigned long id) {
unsigned long i, j, k;
for(i = 0; i < 256; ++i) {
k = i;
for(j = 0; j < 8; ++j) {
if (k & 1) k = (k >> 1) ^ id;
else k >>= 1;
}
table[i] = k;
}
}
벤치마크
4NT의 timer 명령으로 위의 프로그램의 속도를 측정해 보았습니다 (
4NT가 설치되어 있어야 함. / Update 2021-08-18: 4NT 가 지금은 TCC 라는 이름으로 변경됨):
[1] D:\Warehouse\My Virtual Machines>timer & getcrc "Windows 2000 Professional + MSO [v5.5].zip" & timer
Timer 1 on: 3:37:29p
6B517356: Windows 2000 Professional + MSO [v5.5].zip
Timer 1 off: 3:37:49p Elapsed: 0:00:19.83
[0] D:\Warehouse\My Virtual Machines>
782MB (820,136,835 바이트) 라는 큰 파일인데도, 불과 20초가 걸렸습니다. 엄청난 속도입니다.
▶▶ [QnA] ZIP 이나 RAR 파일의, CRC32 란 무엇입니까? / 'CRC 에러'란? / CRC 값을 어떻게 구하나요?
추가 사항:
"Windows 작업 관리자"로 보면, 700메가짜리 파일을 읽을 때에도 getCRC.exe 가 메모리를 고작 644KB 만 차지합니다. 1메가도 채 안되는 것입니다.
tag: cpp
C언어 | C/C++ (Visual C++)