이전에 #define문을 이용한 상수의 정의를 살펴보았는데 이번에는 매크로(macro)를 정의하는 방법에 대해서 알아보겠다. 매크로는 함수와 외형 및 동작하는 방식이 비슷해 보이지만 내부적으로는 크게 다른 방식으로 동작한다.


 매크로는 #define문으로 정의되는데 프로그램 중간에서 정의된 이름을 만나면 해당하는 매크로 코드로 치환된다. 예를 들어서 다음과 같이 매크로를 정의한다.


#define pow3(x) x*x*x


이제 프로그램 중간에 pow3(2) 라고 쓰면 그 명령어가 통채로 2*2*2으로 대체되게 된다. 만약 pow(iA)라고 쓰면 iA*iA*iA로 바뀐다. 외형상 2이라는 숫자나 iA와 같은 변수를 매크로에 x로 인자로 넘길 수 있게 되므로 마치 함수 같아 보이지만 동작 방식은 전혀 다른 것이다.


#include <stdio.h>
#define pow3(x) x*x*x

int main() {
   int iA = 5;
   float fA = 1.5;
   printf("%d**3 = %d \n", 6, pow3(6)); //❶
   printf("%d**3 = %d \n", iA, pow3(iA)); //❷
   printf("%f**3 = %f \n", fA, pow3(fA)); //❸
}
6**3 = 216
5**3 = 125
1.500000**3 = 3.375000


여기서 ❶, ❷, ❸번 줄을 보면 매크로를 마치 함수를 호출하듯이 사용하고 있으나, 사실은 컴파일하기 전에 프로그램을 다음과 같이 단순 치환하여 변형한 것이 불과하다.


printf("%d^3 = %d \n", 6, 6*6*6 );
printf("%d^3 = %d \n", iA, iA*iA*iA );
printf("%f^3 = %f \n", fA, fA*fA*fA );


따라서 함수의 호출과는 동작하는 방식이 전혀 다른 것이다.


 매크로의 인수로는 두 개 이상도 사용가능하다. 다음 예는 두 수들 중에서 작은 수를 찾아주는 매크로이다.


#include <stdio.h>
#define MIN(a, b) (a<b)? a:b
int main() {
   short nA = -10, nB = -15;
   printf("MIN(%d,%d) is %d.\n", 2, 3, MIN(2,3));
   printf("MIN(%d,%d) is %d.\n", nA, nB, MIN(nA, nB));
}
MIN(2,3) is 2.
MIN(-10,-15) is -15.


 매크로는 단순치환이기 때문에 다음과 같은 경우를 주의해야 한다. 다음 예에서 세 숫자의 곱으로 치환하는 매크로를 예로 들어보았다.


#include <stdio.h>
#define MUL1(a,b,c) a*b*c //❶
#define MUL2(a,b,c) (a)*(b)*(c) //❷
int mulF(int, int, int);

int main(void)
{
   short sA = 2, sB = 3, sC = 4, sD1, sD2, sDF;
   sD1 = MUL1(sA+1, sB, sC);//❸
   sD2 = MUL2(sA+1, sB, sC);//❹
   sDF = mulF(sA+1, sB, sC);
   printf("MUL1: %d*%d*%d = %d \n", sA+1, sB, sC, sD1);
   printf("MUL2: %d*%d*%d = %d \n", sA+1, sB, sC, sD2);
   printf("MulF: %d*%d*%d = %d \n", sA+1, sB, sC, sDF);
}

int mulF(int iA, int iB, int iC)
{
   return iA*iB*iC;
}


❶과 같이 매크로를 정의했다면 ❸은 다음과 같이 치환된다.



nD1 = nA+1 * nB * nC;


따라서 의도하지 않은 엉뚱한 계산결과가 nD1변수에 저장되게 된다. 즉, 매크로는 정의된 그대로 치환을 하기 때문에 이와 같은 오류가 발생하는 것이다. 이를 방지하려면 ❷와 같이 각각의 인수에 괄호( )를 쳐주면 된다. 그러면 ❹는 다음과 같이 의도한 대로 치환된다.


nD2 = (nA+1) * (nB) * (nC);


이로서 의도한 계산 결과를 얻을 수 있다. 전체 실행 결과는 다음과 같다.


MUL1: 3*3*4 = 14
MUL2: 3*3*4 = 36
MulF: 3*3*4 = 36


매크로는 함수로 작성하기에는 다소 간단한 기능을 구현하는데 자주 사용된다. 하지만 매크로를 사용할 때에는 위와 같이 문제가 발생할 소지가 있으므로 보통 인수로 사용하는 변수에는 괄호를 꼭 붙여서 사용해야함에 주의해야 한다.


C++ 강좌 전체 목록 >>>


c{c++},n{c000x}

Posted by 살레시오
,

 정적(static) 변수는 전역 변수와 지역 변수의 중간쯤 되는 특성을 가진다. 정적변수도 전역정적 변수와 지역 정적 변수로 나뉘지만 여기에서는 지역 정적 변수에 대해서만 설명하도록 하겠다.


 지역 정적 변수는 함수의 수행이 끝나더라도 그 값을 유지시켜야만 할 때 사용되는 것이다. 즉, 이 변수는 함수의 수행이 끝나더라도 소멸되지 않으며 그 값을 유지하고 있으며 프로그램의 수행이 끝날 때까지 그 값을 유지하는 변수이다.


 정적 변수는 static이라는 키워드를 데이터형 앞에 붙여주면 되는데 다음과 같이 정의한다.


함수() {
   static 데이터형 변수명1, 변수명2, ...;
}


이렇게 정의된 변수들은 프로그램의 수행이 시작될 때 생성되며 함수의 수행이 끝나더라도 그 값이 유지되며 다음에 호출되었을 때 그 유지된 값을 이용할 수 있다. 프로그램이 실행될 때 생성되고 끝날 때 까지 보존이 된다는 점에서 전역 변수와 라이프 싸이클이 같지만 선언된 함수 내부에서만 사용할 수 있다는 점이 다르다.


다음의 예에서 간단한 사용법을 보였다.


#include <stdio.h>
void countUp(int);

int main(void) {
   int iIn;
   do {
       printf("Input an interger number : ");
       scanf("%d", &iIn);
       countUp(iIn);
   }
   while (0<=iIn && iIn<=10);
}

void countUp(int iR) {
   static int iCount = 0; //❶
   printf("%d번째 수는 %d.\n", ++iCount, iR);
}

실행결과:

Input an interger number : 8
1번째 수는 8.
Input an interger number : 4
2번째 수는 4.
Input an interger number : 10
3번째 수는 10.
Input an interger number : 0
4번째 수는 0.
Input an interger number : -1
5번째 수는 -1.


 이 예제는 사용자가 입력한 숫자가 0이상 10이하라면 다시 입력받고 현재까지 몇 개가 입력되었는가를 세는 간단한 프로그램이다. 이 예제의 countUp()함수 안의 ❶번 줄에서 iCount 변수가 정적 변수로 선언되었다. 따라서 이 함수가 종료되더라도 그 값은 계속 유지하며 이 사실은 실행 결과에서 확인할 수 있다.


 내부 정적 변수도 내부 변수이므로 그것이 위치한 함수 내부에서만 접근할 수 있다는 사실은 유의하자.


C++ 강좌 전체 목록 >>>


c{c++},n{c0028}


Posted by 살레시오
,

 변수는 정의된 위치에 따라서 유효한 범위가 결정되는데 크게 전역(global) 변수, 지역(local) 변수로 나눌 수 있다.  C/C++ 프로그램을 작성하다 보면 전 영역에서 (즉, 모든 함수의 내부에서) 공통적으로 접근할 수 있는 변수를 사용해야 하는 경우도 발생하는데 이러한 경우에 전역 변수를 정의하여 사용한다.


다음 예에서 main()함수 위에 선언된 변수들 cA, iA, lA이 전역변수이고 main()함수 내부에 선언된 cB, iB, lB 등이 (main 함수의) 지역 변수이다. 전역 변수가 main()함수 위에서 (밖에서) 정의되었다는 것을 눈여겨 보기 바란다. 반면 지역변수는 함수의 내부에서 정의되었다.


char ca;
int ia;
long la = 1111111;

int main() {
   char cb;
   int ib;
   long lb = la + 2222222;
}


 전역변수는 선언된 부분 아래에 위치하는 어느 함수에서도 사용할 수 있다, 반면 지역변수는 그 변수가 선언된 함수의 내부에서만 사용될 수 있다. 그리고 지역변수는 함수가 시작될 때 생성되며 함수 수행이 끝나면 소멸된다.


  • 전역변수는 프로그램이 시작될 때 생성, 프로그램 종료시 소멸된다.

  • 지역변수는 함수가 시작될 때 생성, 함수 종료시 소멸된다.


 다음 예는 전역변수 icnt를 화면에 표시하는 프로그램 예를 실행시킨 것이다. main()함수 위에 정의된 icnt변수는 전역 변수로서 프로그램이 종료될 때까지 소멸되지 않고 그 아래의 어떤 함수에서도 접근할 수 있으며 그 값을 유지시킨다. 이 예에서 보면 main()함수와 countup()함수 모두에서 전역 변수 icnt를 접근하거나 값을 변경시켰다.


#include <stdio.h>

#include <stdio.h>

int icnt = 0; //전역변수

int main(int argc, char **argv)
{
   while(icnt<10) {
   countup();
   printf("icnt = %d\n", icnt);
   }
}

void countup() {
   icnt++;
}


icnt = 1
icnt = 2
icnt = 3
icnt = 4
icnt = 5
icnt = 6
icnt = 7
icnt = 8
icnt = 9
icnt = 10


 정리하면 다음과 같다. 전역 변수는 함수 외부에서 선언(초기화)하며 그 아래에 있는 모든 함수에서 접근이 가능하다. 지역 변수는 함수 내부에서 선언된 변수이며 함수가 시작될 때 생성되고 종료되면 소멸된다.


C++ 강좌 전체 목록 >>>


c{c++},n{c0028}

Posted by 살레시오
,