It's not even worth asking the rhetorical question, Have you ever had a baffling bug that you just couldn't track down? Of course you have; everyone has. C has a number of splendid “gotcha!s” lurking in wait for the unwary; this chapter discusses a few of them. (In fact, any language powerful enough to be popular probably has its share of surprises like these.)
for (i = start; i < end; i++); { printf("%d\n", i); }
for (i = start; i < end; i++) ; { printf("%d\n", i); }
#if
/ #ifdef
/ #ifndef
/ #else
/
#endif
의
쌍이 맞지 않는지 검사해보기 바랍니다.
(덧붙여 질문 2.18, 10.9, 11.29도 참고하시기 바랍니다.)
myprocedure;C 언어는 함수(function)만을 지원합니다. 그리고 함수에 전달되는 인자가 하나도 없더라도 괄호로 둘러싼 `argument list'를 써 주어야 합니다. 따라서 다음과 같이 써야 합니다:
myprocedure();
또, 프로그램을 잘못 link했을 확률도 있습니다 (각각 다른 컴파일러 옵션을 써서 만든 object module을 합쳤거나, 잘못된 dynamic library를 link했을 경우). 또는 run-time dynamic library linking이 어떤 이유로 실패했거나, main을 잘못 선언했을 수도 있습니다.
(두 번째와 세 번째 문제는 질문 7.5와 밀접한 관계가 있습니다; 덧붙여 질문 11.16도 참고하시기 바랍니다.)
a * b / c
와 같은 연산을 할 때, 계산 도중
overflow가 일어날 때. (덧붙여 질문
3.14도 참고하시기 바랍니다.)
%d
를 써서 long int를 출력하려 한 경우
(질문
12.7,
12.9 참고)
size_t
에 대해. (질문
7.15 참고)
올바른 함수 prototype을 사용한다면 이런 종류의 많은 문제를 미리 잡아낼 수 있습니다; lint를 쓰는 것도 좋은 방법입니다. 덧붙여 질문 16.3, 16.4, 18.4도 참고하시기 바랍니다.
char *p = "hello, world!"; p[0] = 'H';
char a[] = "hello, world!";같은 이유에서, 다음과 같이, 전통적으로 쓰는, UNIX mktemp 쓰임새는 잘못된 것입니다:
char *tmpfile = mktemp("/tmp/tmpXXXXXX");올바른 방법은 다음과 같습니다:
char tmpfile[] = "/tmp/tmpXXXXXX"; mktemp(tmpfile);
struct mystruct { char c; long int i32; int i16; }; char buf[7], *p; fread(buf, 7, 1, fp); p = buf; s.c = *p++; s.i32 = *(long int *)p; p += 4; s.i16 = *(int *)p;
주어진 역할을 좀 더 올바르게 수행할 수 있는 방법은 다음과 같습니다:
unsigned char *p = buf; s.c = *p++; s.i32 = (long *)p++ << 24; s.i32 |= (long *)p++ << 16; s.i32 |= (unsigned)(*p++ << 8); s.i32 |= *p++; s.i16 = *p++ << 8; s.i16 |= *p++;This code also gives you control over byte order. (This example, though, assumes that a char is 8 bits and the long int and int being unpacked from the “external structure” are 32 and 16 bits, respectively.) (비슷한 코드를 보여주는) 질문 12.42를 보기 바랍니다.
“bus error”와 “segmentation violation”의 차이는 중요하지 않습니다; 각각 다른 상황에서 각각 다른 버전의 UNIX는 이러한 시그널들을 만들어 냅니다. 간단히 말해, segmentation violation은, 아예 존재하지도 않는 메모리에 access하려 했다는 것이고, bus error는 메모리를 잘못된 방법으로 access하려 (대개 잘못된 align을 가지는 포인터, 질문 16.7 참고) 했다는 것을 뜻합니다.
Seong-Kook Shin