내용 출처 : YES C (정보공학연구소 /생능출판사)
혼자 연구하는 C/C++ (SoEn.kr /와우북스)
Ⅰ. 전처리기(preprocessor)
① 원시코드가 컴파일되기 전에 C언어의 문법과는 독립적으로 실행시켜 매크로 문장이 있으면 정의된 문장으로 치환해주는 역할을 담당하는 것
② 컴파일하기 전에 코드를 변경시켜주는 역할을 수행하기에 기계어로 번역되지는 않는다.
③ 전처리문은 #으로 시작하고, 다른 문장과는 달리 끝에 ;를 붙이지 않는다.
④ 전처리문은 한행에 하나씩 써야하고, 뒤에 주석을 제외한 다른 것이 올 수 없다.
⑤ 전처리기의 종류와 기본적인 역할은 다음과 같다. (일부분이다. 다음 포스트에서 나머지를 다룰예정이다.)
종류 |
기능 |
#include |
지정파일을 원시 프로그램에 포함시킨다. |
#define |
지정 문자열을 매크로로 정의하여 치환 |
#undef |
지정 매크로를 취소 |
#if / #elif / #else / #ifdef / #ifndef / #endif |
조건에 따라 원시프로그램의 일부분을 선택하여 분할 컴파일 |
Ⅱ. #include
① 지정된 파일의 내용을 그 위치에 기술한 것으로 처리한다.
② (1) #include <파일명>, (2) #include "파일명" 의 형식으로 사용한다.
Ⅲ. #define
① 매크로 상수나 함수를 정의하기 위해 사용된다.
② '#define 매크로명 실제값'의 형태로 사용하면 매크로명이 적혀있는 부분을 실제값으로 단순 치환한다.
③ #define O 1 이라고 정의했다고 문자 상수 'O'나 문자열 상수 "O"이나 DRONE 같은 형태로 있는 곳이 치환되지는 않는다.
④ 매크로명을 지을 때는 식별자를 지을 때의 규칙이 적용되며, 다른 식별자 명과 중복되어서는 안된다.
⑤ 매크로명에는 공백이 포함될 수 없지만 실제값에는 공백이 포함될 수 있다.
⑥ '#define 매크로명(인수) 매크로함수'로 정의하면 매크로 함수를 정의할 수 있다. (설명한 적이 있으므로 생략)
⑦ 매크로 함수가 아니더라도 매크로의 값이 수식이라면 괄호로 싸줘야지 예상치 못한 오작동을 막을 수 있다.
⑧ 매크로의 값 안에 미리 정의한 매크로명을 사용할 수도 있다.
⑨ 값을 가지지 않는 매크로도 정의할 수 있다. 주로 밑에 나올 분할 컴파일에 사용된다.
⑩ 매크로는 소스코드 전체에 영향을 끼치므로 자주 사용되는 상수값을 지정하는데만 쓰는게 좋다.
⑪ 범위를 지정할 수 있는 const변수나 enum변수로도 #define문과 같은 효과를 볼 수 있음을 기억하자.
⑫ 매크로 상수명은 대문자로 쓰는 관습이 있다.
Ⅳ. #undef
① 지정한 매크로를 해제할 때 사용한다.
② 이미 정의한 매크로의 값을 바꿔야 할 때 사용한다.
③ #define은 중복되면 에러가 나지만 #undef는 안나므로
다른 파일에서 자신이 정의한 매크로 상수를 다른 파일에서 쓰고 있을 수 있는 가능성이 있으면 #undef를 써두는 것이 좋다.
!! (vs 2017 기준으로 #define의 중복이 경고 1레벨로 내려가고, 새롭게 정의된 것으로 사용되도록 바뀐듯 하다. 물론 호환성을 위해 위의 방법을 쓰는 것이 좋다.)
Ⅴ. #if, #elif, #else, #endif
① if, else if, else 같은 조건을 지정하는 전처리문으로 조건에 맞는 경우에만 그 부분을 컴파일한다.
② if문에서는 괄호로 범위를 지정하지만 전처리문에는 괄호가 적용되지 않으므로 #endif로 범위가 끝났음을 나타낸다.
③ 조건식의 사용 또한 if문과 거의 동일하므로 다른 점만 정리한다.
④ #if문에서는 조건식에 괄호를 적지 않아도 된다. 하지만 쓰는 쪽이 권장된다.
⑤ 비교식에서 비교 대상에 실수값이나 문자열값은 쓸 수 없다. 조건부 컴파일의 비교식의 숫자는 표식에 가까우므로 큰 의미도 없다.
⑥ 나머지 연산이나 비트 연산등은 가능하나 ++, --, 포인터 연산, sizeof, 캐스트 연산 등은 쓸 수 없다.
매크로는 상수이므로 좌변값이 아니고, sizeof나 포인터 연산 등은 컴파일시에 평가되기 때문이다.
⑦ defined 연산자로 매크로의 존재 여부도 확인할 수 있다. (#if defined MACRO는 밑에 나올 #ifdef MACRO랑 완전히 동일하다.)
⑧ #ifdef는 다른 조건과 사용할 수 없으니 다른 조건과 함께 비교할 때는 위의 방법을 써야한다.
⑨ defined 연산자는 전처리문 구문에서만 사용할 수 있다.
⑩ if문이 중첩이 가능하듯이 #if문도 중첩해서 사용할 수 있다. 이때, 닫는 괄호에 해당하는 #endif을 #if문 숫자에 맞춰서 써주는 것을 잊으면 안된다.
⑪ if문에 대해서는 들여쓰기를 하지만 #if는 중첩되도 들여쓰기를 하지 않는게 관례이다.
⑫ #if문의 활용 예는 어떤 문제에 대한 해결책이 3가지가 있고 각각의 성능을 테스트 해보고 싶을 때 사용하면 코드를 수정하지 않고 매크로 조건문만 바꿔보면 된다.
⑬ 고객이 원하는 방법이 각각 다르다면 그에 맞춰서 컴파일해주기도 이렇게 하는게 편하다.
⑭ #if 0 은 언제나 거짓이므로 매우 긴 구간을 주석 처리할 때 사용할 수 있다. /* */는 중첩이 안 된다는 문제가 있지만 #if 0은 중첩이 가능하다는 장점도 있다.
Ⅵ. #ifdef, #ifndef
① 매크로가 정의되어 있는지를 확인하고 정의되어 있을때나 정의되어 있지 않을때만 그 부분을 컴파일하는 전처리문이다. #endif가 닫는 괄호 역할을 한다.
② 매크로가 정의되어 있는 경우는 #ifdef macro 로, 정의되어 있지 않은 경우는 #ifndef macro로 구분한다.
③ 똑같은 프로그램의 일반 버전과 프로 버전이 있고 프로버전에만 새로운 기능을 추가해주려 하는 경우 #define pro를 선언하고
프로버전에만 들어갈 기능은 #ifdef pro로 묶어두면 일반 버전을 컴파일 할 때는 #define pro를 빼면 일반 버전용이
프로버전을 컴파일할 때는 #define pro를 넣어주면 프로버전용이 만들어진다.
④ 만약 여기에서 일반버전에만 기능을 추가해주고 싶다면 그 부분을 #ifndef pro로 묶어주면 된다.