자료출처: 핵시 길잡이 C 프로그래밍 언어
도서출판: 성안당
선행처리기란 프로그래머와 컴파일러 사이에서 매개 역할을 수행하며, C 프로그램을
컴파일하기 전에 프로그래머가 작성한 원시 프로그램에 특정하게 정의된 각종 내용을
삽입시키는 기능을 하는 처리기를 말한다.
선행처리기 정의는 # 기호로 시작된다. 프로그램 상에서 정의하는 위치는 특별히 정
해져 있지 않지만 일반적으로 첫 칸부터 지정하며 그 문장의 끝에는 세미콜론 ( ; ) 을
붙이지 않는다. 또한 하나의 명령은 한 줄에서만 가능하다. 예를 들면,
# define PI 3.141592
라고 정의하였다면 선행처리기는 프로그램에 사용된 PI 를 모두 3.141592로 치환한 후
원시 코드를 번역하게 된다. 여기서 # define 문은 상수를 선언한 것처럼 보이지만 사
실상 선언문이 아니라 치환하라는 의미를 가지는 매크로 ( macro ) 이다.
매크로 등의 선행처리기를 사용하는 근본적인 이유는 보다 효율적인 프로그램을 작
성할 수 있고, 프로그램의 이식성과 이해를 증진시킬 뿐만 아니라 일반 함수를 사용할
때보다 수행 속도가 빠르기 때문이다. 이러한 선행처리기는 매크로의 정의 ( # define ),
파일의 첨가 ( # include ), 조건부 컴파일 등이 있다.
복잡한 문장이나 여러 줄에 걸쳐 기술된 문장을 하나의 문장으로 정의하여 사용하는
것을 매크로 ( macro ) 라 한다. 일반적으로 매크로는 변수와 구분하기 위하여 대문자를
사용하여 기술한다. # define 문은 이러한 매크로를 원시 프로그램에 정의하는 데 사용
하는 선행처리기이다. 즉 # define 으로 정의되어 있는 매크로를 원시 프로그램 내에서
검색하여 검색된 매크로를 모두 정의한 문자열로 치환시킨다. 따라서 C 언어에서 프로
그램의 처음에 매크로명을 정의해 두면 나중에 그 값을 일일이 지정하지 않아도 된다.
# define 사용 시 몇 가지 유의해야 할 사항이 있다.
1. # define 정의는 프로그램에서 첫 칸에 # 기호로 시작되며 원시 프로그램 내의
어느 곳에서나 지정할 수 있다. 이때의 유효 범위는 정의한 곳에서부터 그 프로그램
의 끝까지이다.
2. 매크로명은 일반 변수와 구별하기 위해 보통 대문자를 많이 사용한다. 이때 지정
하는 매크로명 중간에 공백을 두어서는 안 된다. ( 매크로명을 소문자로 지정하여
도 문법적인 오류 ( error ) 는 발생하지 않는다. )
3. C 언어에서는 문장의 끝을 세미콜론 ( semicolon : ' ; ) 으로 나타내는 데 반해
# define문의 끝에는 세미콜론 ( ; ) 을 붙이지 않는다. 만약 세미콜론을 붙이면 세
미콜론까지도 치환할 문자열로 간주한다. 이때 컴파일러 에러는 발생하지 않지만
프로그래머의 의도와 달라질 수 있다.
4. # define 지정은 한 줄 내에서만 가능하다. 만약 한 줄에 매크로명과 치환 문자
열을 전부 쓸 수 없으면 줄의 끝에 역슬래쉬 ( \ ) 를 하여 다음 줄에 계속 지정할
수 있다.
5. 매크로를 문자열 상수 즉, 이중 인용부호 ( " " ) 사이에 지정하면 # define 에 지정
한 치환 문자열로 치환되지 않는다.
6. 매크로명과 인수를 기입하기 위한 괄호 사이에 공백 ( blank ) 을 두어서는 안 되며,
문자열 전체를 괄호 속에 넣어서도 안 된다.
인수 없이 사용되는 # define의 일반 사용 형식은 다음과 같다.
형식 |
# define < 매크로명 > < 치환 문자열 > |
예 |
1. # define TRUE 1 |
선행처리기를 사용하여 문자 상수와 문자열 상수를 정의할 때에는 다음과 같이 각각
단일 인용부호 ( ' ' )와 이중 인용부호 ( " " )로 묶어서 처리한다.
# define 매크로명 ' 문자 상수 '
# define 매크로명 " 문자열 상수"
예 |
# define STOP ' @ ' |
|
선행처리기는 인수를 포함한 매크로도 허용한다. 즉 함수처럼 상황에 따라 인수를
지정하여 원하는 결과를 얻을 수 있다. 이를 인수를 갖는 매크로 또는 매크로 함수
( macro function ) 라 한다.
인수가 있는 # define 의 일반 사용 형식은 다음과 같다.
형식 |
# define 매크로명 ( 가인수 1, 가인수 2, ....... ) < 치환 문자열 > |
결과적으로 매크로명은 매개변수 ( parameter ) 를 갖고 있어 매크로명이 호출될 때마다
가인수 ( formal parameter ) 가 실인수 ( actual parameter ) 로 치환된다. 특히 주의할 것은
매크로명과 매개변수를 나타내는 괄호 사이에 공백이 있어서는 안 된다. 공백이 있는 경
우에는 이것도 치환 문자열로 인식하게 된다. 또한 치환 문자열에서 매개변수 내용의 전
체 및 각 요소 자체도 괄호를 삽입해야 원하는 연산 결과를 얻을 수 있다.
또한 매개변수로 ++a 와 같은 증감 연산자는 결과를 예측할 수 없으므로 사용하지
않는 것이 바람직하다.
|
|
매크로 확장인 경우에는 ( ) 를 사용하는 것이 좋다. 이것은 문법적으로 규정하는 것
은 아니지만 안전 측면 몇 프로그램의 이해도를 증진시키므로 필요에 따라서 ( ) 를 적
절하게 사용하는 것이 좋다.
|
|
위 예제에서 SQUARE ( a + 1 ) 을 매크로 # define SQUARE ( X ) X * X 에
대입하면 수식은 다음과 같다.
a + 1 * a + 1
여기서 연산의 우선 순위를 적용하면 다음과 같다.
이 때 a = 7 을 대입하면 7 + 1 * 7 + 1 = 15 가 된다.
|
|
위 두 예제 에서 SQUARE ( a + 1 ) 을 매크로 # define SQUARE ( X ) ( X ) * ( X )
에 대입하면 수식은
( a + 1 ) * ( a + 1 )
과 같다. 여기서 연산의 우선 순위를 적용하면 괄호가 우선 순위가 높기 때문에 다음과
같다.
따라서 a = 7 을 대입하면 ( 7 + 1 ) * ( 7 + 1 ) 이므로 결과는 64가 된다. 그러므로 매크로
확장의 경우 ( ) 를 적절하게 사용하여야 정확한 연산 결과를 얻을 수 있다.
# include 문은 C 언어의 선행처리기 명령의 하나로서 , 파일을 포함하는 명령이다.
# include 다음에 지정한 파일명의 내용 즉 , 지정한 # include 문의 파일들을 현재의 원
시 파일에 포함시킨다. 일반 형식은 다음과 같다.
형식 1 |
# include < 파일명 > |
형식 1 은 파일을 검색할 때 하나 또는 그 이상의 표준 디렉토리에서 파일을 찾으며 ,
주로 \include 디렉토리에 있는 공용 파일을 포함시킬 때 선언한다. 시스템에서 제공하
는 < stdio.h > < math.h > < graphics.h > 등의 헤더 파일을 포함시킬 때 주로 사용하게
된다.
형식 2 |
# include " 파일명 " |
형식 2 는 프로그래머가 정의한 헤더 파일을 포함시킬 때 주로 사용된다. 이 때 " 파일
명 " 은 현재 사용 중인 디렉토리 또는 정해진 디렉토리에서 먼저 파일을 찾고 , 현재의
디렉토리에 없으면 시스템 디렉토리에서 찾게 된다.
예 |
|
|
# undef 는 가장 최근에 정의된 매크로명을 해제할 때 사용되며 그 형식은 다음과
같다.
형식 |
# undef < 매크로명 > |
만약 똑같은 매크로명이 다른 값으로 정의되었을 때 # undef < 매크로명 > 이 정의되었다.
면 그 전에 정의된 값으로 환원되어 스택 ( stack ) 에 있어서의 push 와 pop 의 개념과 같다.
예 |
# define MAX 100 // 매크로 MAX 정의 |
조건부 컴파일은 특정 조건을 만족하는 경우에만 C 프로그램의 소스 코드를 번역한
다. 이러한 의미로 # if 와 # endif 이 사용된다.
형식 1 |
|
선행처리기에서 { } 는 사용할 수 없기 때문에 # if 와 # endif 를 사용한다. 수식 1의 값이
참이면 # if 와 # else 사이의 명령문을 실행하지만 , 만족하지 않으면 # else 와 # endif 사
이의 명령문이 실행된다. 따라서 이러한 구조는 if ~ else 제어문의 구조와 비슷하다.
|
형식 2 매크로가 정의된 경우 |
# ifdef 매크로명 |
형식 3 매크로가 정의되지 않는 경우 |
# ifndef 매크로명 |
|
예제 에서 # define AGE 20이 선언되어 있으므로 # ifdef AGE 문에서 조건을
만족하여 printf ( " 나이 = %d\n " , AGE ) ; 문장이 수행되었다. 그런데 #ifndef AGE
문장은 AGE 매크로가 정의되지 않았을 경우에만 다음 명령문이 수행되기 때문에 현
재 조건을 만족하지 않게 된다. 따라서 명령문 printf ( " 나이가 불확실합니다. \n " ) 는 수
행되지 않는다.