1 /* memcpy -- 겹치지 않는 메모리 블록을 복사한다. */
2
3 void *memcpy(void *pvTo, void *pvFrom, size_t size)
4 {
5 void *pbto = (void *)pvTo;
6 void *pbFrom = (void *)pvFrom;
7
8 if(pvTo == NULL || pvFrom == NULL){
9 fprintf(stderr, "bad args in memcpy\n");
10 abort();
11 }
12 while(size-- > 0)
13 *pbTo++ = *pbFrom++;
14 return (pvTo);
15 }
16
17
18 /*
19 * 위의 프로그램은 void * 변수들이 NULL을 가리키고 있을시의 exception 처리를
20 * 보여주고 있다. 헌데, 저 줄은... 낭비가 아니라고 할수가 없다....
21 * 낭비이다!!!!! debug할때는 필요하지만 배포용으로 컴파일 할때는 필요가 없다
22 * 그래서!!!!
23 * 다음과 같이 #ifdef , #endif 를 이용하여 DEBUG가 정의되었을 때만 실행하도록
24 * 변경하자~~~~~~~~~~
25 */
26
27 void *memcpy(void *pvTo, void *pvFrom, size_t size)
28 {
29 void *pbto = (void *)pvTo;
30 void *pbFrom = (void *)pvFrom;
31
32 #ifdef DEBUG
33 if(pvTo == NULL || pvFrom == NULL){
34 fprintf(stderr, "bad args in memcpy\n");
35 abort();
36 }
37 #endif
38 while(size-- > 0)
39 *pbTo++ = *pbFrom++;
40 return (pvTo);
41 }
42
43 /* 자~ 이젠 Debug할때만 (DEBUG가 정의되어 있을때만) 저 안의 구문이 실행되도록
44 * 바꾸어 보았다! 쉽다... ㅋㅋㅋㅋ
45 * 헌데~ 오늘 말하고 싶은 내용은 이 7줄의 #ifdef 와 #endif 안의 내용을 한줄로
46 * 처리할 수 있다. assert()는 ANSI assert.h 헤더 파일에 정의되어 있는 assert라는
47 * 이름의 매크로에 숨겨 두기 때문이다.
48 * assert는 우리가 앞에서 보았던 #ifdef 코드를 재구성한 형태에 불과하다~~~~!!!!
49 * 한줄로 바꾸어 볼까?
50 */
51
52 void *memcpy(void *pvTo, void *pvFrom, size_t size)
53 {
54 void *pbto = (void *)pvTo;
55 void *pbFrom = (void *)pvFrom;
56
57 assert(pvTo != NULL && pvFrom != NULL);
58
59 while(size-- > 0)
60 *pbTo++ = *pbFrom++;
61 return (pvTo);
62 }
63
64
65
66 /*--------------------------------------------------------------------------------
67 * assert 이용시 주의사항
68 *
69 * assert는 단지 집어넣기만 하면 되는 매크로는 아니다. 이것은 조심스럽게 정의해서
70 * 프로그램의 판매용과 디버그 버전 사이에 중대한 차이를 야기하지 않도록 해야 한다.
71 * assert는 메모리를 혼란시키지 말아야 하고 그냥두면 초기화되지 않는 데이터를
72 * 초기화해야 한다. 그렇지 않으면 어떤 부작용을 일으킬 수도 있다.
73 * 이것이 assert가 함수가 아니고 매크로인 이유이다.
74 * assert가 함수라면, 이것을 호출하면 예기치 않은 메모리나 코드스워핑(swapping)을
75 * 발생시킬 수 있다. assert를 사용하는 프로그래머는, 이것을 시스템이 어떤 상태에
76 * 있든 안전하게 사용할 수 있는 무해한 검사로 본다는 점을 기억해야 한다.
77 * ------------------------------------------------------------------------------*/
78
79
80
81 /* assert를 직접 정의하여 자신만의 assert를 만들어 DEBUG용으로 쓸수있다*/
82 #ifdef DEBUG
83 void my_assert(char *, unsigned); /* 원형 */
84 #define ASSERT(f) \
85 if (f) \
86 NULL; \
87 else
88 my_assert(_FILE_,_LINE_)
89 #else
90 #define ASSERT(f) NULL
91 #endif
92 /* ASSERT가 실패했을 때, 이것은 선행처리기에 의해, _FILE_과 _LINE_ 매크로를 통해
93 * 제공되는 파일 이름과 행번호를 갖고 my_assert를 호출한다.
94 * my_assert는 stderr에 에러 메시지를 표싷고 수행을 중단시킨다.
95 */
96
97 void my_assert(char *strFile, unsigned uLine)
98 {
99 fflush(stdout);
100 fpinrtf(stderr, "\nAssertion failed : %s, line %u\n",
101 stdFile, uLine);
102 fflush(stderr);
103 abort();
104 }
105
|
⊙ 요약 ⊙
◇ 프로그램을 판매용과 디버깅용의 두 가지 버전으로 관리한다. 판매용 버전은 군더더기 코드를
빼고 날씬하게 유지한다. 그러나 버그를 빨리 발견하기 위해 가능한 한 디버깅 버전을 사용한다.
◇ assertion은 디버깅 검사 코드를 작성하는 속성의 방법이다. 결코 발생하지 않을 규정에 어긋나
는 조건(illegal condition)을 발견하기 위해 이를 사용한다. 이들 조건(illegal condition)과 에
러 조건(error condition)을 혼동하지 않도록 주의한다. 익서은 최종적인 프로그램에서 처리해
야 한다.
◇ 함수의 인자(argument)의 유효성을 검사하고, 프로그래머들이 정의되지 않은(undefined) 어
떤 작업을 하면 경고하기 위해 assertion을 사용한다. 여러분의 함수들을 보다 엄격하게 정의할
수록, 인자의 유효성을 검사하는 것이 보다 쉬워진다.
◇ 일단 함수를 작성하면, 그것을 재검토하고 스스로에게 "나는 무엇을 가정하는가?"라고 묻는다.
가정한 것이 있다는 것을 발견하면, 여러분의 가정이 항상 유효한지 assert하거나, 또는 가정을
제거하기 위해 코드를 재작성한다. 또한 "이 코드에서 가장 잘못될 만한 것은 무엇인가? 그리고
그 문제를 어떻게 하면 자동으로 발견할 수 있는가?"를 묻는다. 가능한 한 가장 빠른 시간에 버
그를 발견하는 검사를 구현하도록 노력한다.
◇ 교과서는 프로그래머에게 방어적으로 프로그램을 작성하도록 권고한다. 그러나 이러한 코딩 방
식은 버그를 감춘다는 점을 기억해야 한다. 벙어적인 코드를 작성할 때는, "발생할 수 없는" 경
우가 발생할 경우, 경고해 줄 수 있는 assertion을 사용한다. |