mwultong Blog ... 프로그래밍 / 계산기

컴퓨터 엑셀 워드 포토샵 구글어스 WINDOWS JAVASCRIPT JAVA C++

 
Tuesday, May 23, 2006

C언어] 비주얼C로, 파일의 CRC32 값 구하기 (빠르고 메모리 점유 없이)


제가 몇 년 전에 외국 사이트에서 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++)

2 Comments:
At January 7, 2007 at 11:29 AM, Anonymous Anonymous said...

안녕하세요. crc32 알고리즘을 한번 짜보려고 구글링하다가 들어왔습니다. 코드에서 보니까요. crc계산을 위한 테이블을 buf에 데이터를 불러서 계산할 때마다 새로 만들게 되더라구요. 그래서 "같은 테이블이 생성되는게 아닌건가?"라는 의문을 가졌는데 코드를 보니 같은 테이블이더군요. 그래서 한번만 테이블을 생성하도록 변경했더니 crc를 계산하는데 더 빠른 결과를 얻을 수 있었습니다. 그럼 좋은 글 잘 보고갑니다.

 
At January 7, 2007 at 12:54 PM, Blogger mwultong said...

그런 문제가 있었군요..
지적해 주셔서 감사합니다.

(∩_∩;)

 

<< Home RSS 2.0 feed

구글 Google 에서 제공하는 무료 블로그 서비스인 블로거 Blogger 의 인터넷 주소는 www.blogger.com 입니다. Blogger 에 블로그를 만들면, blogspot.com 이라는 주소에 블로그가 생성됩니다.
블로그를 직접 방문하지 않고도 최신 게시물을 구독하려면 RSS 2.0 feed 주소를 리더기에 등록하시면 됩니다.
Previous Posts
Monthly Archives
Top