나 같은 경우 일단 돌아가는 코드를 만들고 돌아가는지 눈으로 확인한다음 손을 보는 스타일이라서, 나중에 많은 잔손질 - 거창하게 리팩토링 -을 하게 된다. 이때 모듈화와 함께 가장먼저 손쉽게 진행할 수 있는게 경고메시지를 제거하는 것이다. 이 문서는 gcc(:12) 4.0.x 를 기준으로 작성되었다.
gcc라면 다음과 같은 옵션을 이용해서 경고메시지를 출력하도록 할 수 있다.
보통은 -Wall 옵션만을 사용하는 경우가 많을 것이다. 그러나 경고메시지는 다양한 영역을 가지고 있으다. -Wall 의 all에 속지 말기 바란다. all이라는 단어가 붙은것 과는 다르게, 일부영역의 경고메시지만을 출력해준다. 예를 들면 아래와 같이 리턴값이 명시되지 않은 경우 경고메시지를 출력한다.
int foo (unsigned int x)
{
int y;
if (y < x) x=x+2;
else x= x+1;
}
-Wall 옵션을 주고 컴파일 해보자.
# gcc -Wall -c foo.c
foo.c: In function `foo':
foo.c:6: warning: control reaches end of non-void function
그러나 if (y < x)에서 unsigned와 signed와의 비교와 같은 경고는 잡아내지 않는 것을 알 수 있다. 결국 모든 경고메시지를 없애고 싶다면, 다양한 종류의 경고옵션을 함께 사용해야 한다.
-W
signed 와 unsigned의 비교. 조건문에서 body가 명시되지 않거나, 결코도달할 수 없는 조건문등을 찾아낼 수 있다. 아래의 코드는 컴파일되고 실행되는데 전혀 문제는 없을 것이다. 그러나 if (x < 0) 문은 결코 만족할 수 없다. 이러한 코드는 버그를 만들어낼 수 있을 것이다.
int foo (unsigned int x)
{
if (x < 0)
return 0; // 결코 도달할 수 없다.
else
return 1;
}
-Wall 옵션을 이용하면 경고메시지가 출력되지 않을 것이다.
# gcc -Wall -c foo.c
그러나 -W 옵션을 이용하면 다음과 같은 경고메시지가 출력되는걸 확인할 수 있다.
# gcc -W -c foo.c
foo.c: In function `foo':
foo.c:4: warning: comparison of unsigned expression < 0 is always false
일반적으로 -W 옵션은 -Wall 옵션과 함께 사용한다.
-Wconversion
이 옵션은 형변환(type conversion)과 관련되어서 잘못 사용된 코드에 대한 경고를 잡아낸다. floating-point와 integer, long과 short integers 사이의 형변환과 같은 것들이다. 예를 들어서 abs()는 실수형 정수에 대해서 절대값을 리턴하는 함수이다. 만약 인자로 float(:12)값을 입력한다면 원하지 않는 결과가 출력될 것이다.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
double x = -3.14;
double y = abs(x); /* fabs(x)를 사용해야 함. */
printf ("x = %g |x| = %g\n", x, y);
return 0;
}
-Wall 옵션을 주고 컴파일 하면, 경고메시지를 출력하지 않을 것이다. 그러나 프로그램을 실행시키면 잘못된 결과를 보여주게 된다.
# gcc -Wconversion -o abs abs.c
abs.c: In function ‘main’:
abs.c:7: warning: passing argument 1 of ‘abs’ as integer rather than
floating due to prototype
abs() 함수대신에 fabs()함수를 이용하면, 위 코드의 논리적오류를 수정할 수 있다.
이 외에도 -Wconversion 옵션은 변수에 잘못된 값을 할당하는 오류도 찾아낸다.
unsigned int x = -1;
기술적으로 ANSI/ISO:::C(:12) 표준은 위의 코드를 허용한다. 그러므로 대부분의 컴파일러가 에러없이 컴파일을 해준다. 그러나 코드가 제대로 작동할지는 보장할 수 없다.
-Wshadow
이것은 선언된 변수명을 다른 scope에서 다시 선언한 경우 경고를 발생시킨다. 이렇게 변수가 선언될 경우 이것을 shadowing변수라고 한다. 다음의 코드를 확인해 보도록 하자.
#include <stdio.h>
double test (double x)
{
double y = 1.0;
{
double y;
y = x;
}
return y;
}
int main (void)
{
printf("%lf\n", test(5.0));
}
2개의 scope에서 y변수가 선언되었음을 알 수 있다. 이경우 비록 이름은 같지만, scope가 다르므로 전혀다른 변수 이름 테이블을 가지게 된다. 당신이 사용하는 컴파일러가 ANSI/ISO C를 준수한다면, 1을 리턴할 것이다. shadowing 변수의 사용자체가 문제가 되는건 아니지만, 보통의 경우 실수로 사용하는 경우가 많으므로 -Wshadow 옵션을 이용해서 제거하도록 하자.
# gcc -Wshadow -o abs abs.c
abs.c: In function ‘test’:
abs.c:7: warning: declaration of ‘y’ shadows a previous local
-Wcast-qual
const와 같은 타입 제한자를 잘못 사용했을 경우 경고메시지를 출력한다. 아래의 코드와 같은 경우다.
#include <stdio.h>
void f (const char * str)
{
char * s = (char *)str;
s[0] = '\0';
}
int main()
{
char *a = "hello World";
f(a);
}
이 프로그램은 아무런 문제없이 컴파일 될 것이다. 그러나 실행시키면 segmentation fault를 출력하고 종료되어 버릴 것이다. 오히려 위의 경우는 프로그램이 죽어버림으로 즉시 문제를 찾을 수 있으니 큰 문제가 되지 않을 것이다. 다음과 같은 경우가 문제가 된다.
-W
-Wconversion
-Wshadow
-Wcast-qual
-Wtraditional
경고메시지 제거
댓글
Recent Posts
Archive Posts
Tags