C 과제: 매크로의 활용 #2

3 분 소요

질문

내용

직사각형의 면적을 구하는 함수 매크로와 원의 면적을 구하는 함수 매크로를 정의하고, 각각을 이용하는 프로그램을 작성하시오.

공식

직사각형 면적

\[\text{width} \times \text{height}\]

원 면적

\[radius \times radius \times \pi\]

실행 결과

도형의 종류(1.직사각형 2.원 0.종료)? 1
가로 세로? 5 10
면적: 50
도형의 종류(1.직사각형 2.원 0.종료)? 2
반지름? 2
면적: 12.566368
도형의 종류(1.직사각형 2.원 0.종료)? 0

답변

내용

이 문제도 공식이 주어져 있어 쉽게 풀이가 가능하다.

사용자로부터 직사각형의 가로와 세로의 길이를 입력받을 수 있는 변수, width와 height를 정수형으로,

원의 반지름을 입력받을 수 있는 변수, radius도 정수형으로 main 함수 내에 선언하자.

(필자는 정수형에서 보편적으로 많이 사용하는 int형을 선택했다.)

int main(void) {
    int width, height;
    int radius;
}

또한, 실행결과에서처럼 사용자로부터 메뉴를 입력받아 그에 따라 흐름이 분기되고 있으므로, 메뉴 저장을 위한 변수 select도 정수형으로 main 함수 내에 선언해주자.

int main(void) {
    int width, height;
    int radius;
    
    int select;
}

그리고 메뉴 입력 메시지를 출력하는 출력문과 메뉴를 입력하기 위한 입력문도 작성해주자. (물론 입력 함수와 출력 함수를 사용하기 위해서 stdio.h 헤더파일 선언도 잊지 말자.)

#include <stdio.h>

int main(void) {
    int width, height;
    int radius;

    int select;

    printf("도형의 종류(1.직사각형 2.원 0.종료)? ");
    scanf("%d", &select);
}

이제 사용자로부터 입력받은 메뉴에 따라 프로그램의 흐름을 분기시켜줘야 한다.

이를 위해 필자는 switch문을 선택하여 다음과 같이 흐름을 분기시켜주었다.

switch(select) {
    case 0:         // select 값이 0이면, 즉 사용자가 정수 0을 입력했다면,
        break;

    case 1:         // select 값이 1이면, 즉 사용자가 정수 1을 입력했다면,
        break;

    case 2:         // select 값이 2이면, 즉 사용자가 정수 2를 입력했다면,
        break;
}

각 흐름들에 따른 적절한 실행문을 삽입하기 전에 직사각형 면적을 구해주는 함수 매크로부터 작성해보자.

필자는 전처리기가 다음의 구문 형식을 만나면,

SQUARE(X, Y)

다음과 같이 직사각형의 면적을 구하는 식으로 대체되게끔 하기 위해

X*Y

매크로를 다음과 같이 작성했다.

#define SQUARE(X, Y) X*Y

표면적으로 문제가 없는 코드처럼 보이나, 다음의 문제들이 존재한다.

만약 필자가 다음과 같은 구문을 작성했다고 가정해보자.

SQUARE(width+1, height+1)

필자의 의도는 전처리기에 의해 다음의 계산식으로 대체되기를 원했으나,

(width+1)*(height+1)

실제 대체 결과는 다음과 같이 된다.

width+1*height+1

이것은 전처리기의 특성(치환)에 기인한 문제이기 때문에 이를 해결하기 위해서는 매크로 함수를 다음과 같이 작성해야 한다.

#define SQUARE(X, Y) (X)*(Y)

또한, 만약 지금처럼 곱셈(*) 연산자가 아닌 뺄셈(-)이나 덧셈(+) 연산자인 상황에서 곱셈(*) 연산자와 같이 우선순위가 더 높은 연산자가 존재하는 상황일 때는 어떨까?

즉, 아래와 같이 두 피연산자 간의 뺄셈 연산을 수행하는 함수 매크로가 존재했을 때,

#define SUBTRACT(X, Y) (X)-(Y)

다음의 연산을 수행한다면, 어떻게 될까?

SUBTRACT(X, Y) * 5

의도했던 것처럼 다음의 식이 계산되는 것이 아닌,

(X-Y)*5

다음과 같이 계산이 진행되어 전혀 엉뚱한 결과값이 도출된다.

X-Y*5

이것 역시 전처리기의 특성(치환)에 기인한 문제이고, 이러한 상황을 미연에 방지하기 위해서라도

다음과 같이 전체적으로 매크로를 한번 더 괄호로 감싸주자.

#define SQUARE(X, Y) ((X)*(Y))

이러한 매크로의 주의사항만 숙지한다면 원의 면적을 구하는 함수 매크로의 작성도 그리 어렵지 않다.

직사각형의 면적을 구하는 매크로 함수를 작성했던것과 같이 원의 면적을 구하는 매크로 함수를 작성해보자.

(지금까지의 내용을 통해 독자 여러분께서 충분히 이해하셨을 것으로 판단해 중간의 사고과정은 생략했다.)

#define CIRCLE(R) ((R)*(R)*3.14)

매크로 함수의 작성이 완료되었으니 각 흐름에 적절한 실행문을 작성해주자.

switch(select) {
    case 0:         // select 값이 0이면, 즉 사용자가 정수 0을 입력했다면, 이는 종료 항목 선택을 의미하므로
        return 0;       // exit() 함수를 사용해도 된다.
        break;

    case 1:         // select 값이 1이면, 즉 사용자가 정수 1을 입력했다면, 이는 직사각형 항목 선택을 의미하므로
        printf("가로 세로? ");
        scanf("%d %d", &width, &height);

        printf("면적: %d\n", SQUARE(width, height));
        break;

    case 2:         // select 값이 2이면, 즉 사용자가 정수 2를 입력했다면, 이는 원 항목 선택을 의미하므로,
        printf("반지름? ");
        scanf("%d", &radius);

        printf("면적: %f\n", CIRCLE(radius));
        break;
}

또한, 실행결과를 통해 알 수 있듯이 0이 입력되기 전까지는 계속해서 프로그램이 동작해 사용자로부터 메뉴를 입력받아야 하므로, main 함수 내부의 변수 선언문 아래를 무한 루프로 작성해줘야 한다.

이를 반영한 전체코드를 보이면서 이번 포스팅을 마무리 짓겠다.

전체 코드

#include <stdio.h>

#define SQUARE(X, Y) ((X)*(Y))
#define CIRCLE(R) ((R)*(R)*3.14)

int main(void) {
    int width, height;
    int radius;

    int select;

    while(1) {
        printf("도형의 종류(1.직사각형 2.원 0.종료)? ");
        scanf("%d", &select);

        switch(select) {
            case 0:         // select 값이 0이면, 즉 사용자가 정수 0을 입력했다면, 이는 종료 항목 선택을 의미하므로
                return 0;       // exit() 함수를 사용해도 된다.
                break;

            case 1:         // select 값이 1이면, 즉 사용자가 정수 1을 입력했다면, 이는 직사각형 항목 선택을 의미하므로
                printf("가로 세로? ");
                scanf("%d %d", &width, &height);

                printf("면적: %d\n", SQUARE(width, height));
                break;

            case 2:         // select 값이 2이면, 즉 사용자가 정수 2를 입력했다면, 이는 원 항목 선택을 의미하므로
                printf("반지름? ");
                scanf("%d", &radius);

                printf("면적: %f\n", CIRCLE(radius));
                break;
        }
    }
}

댓글남기기