Presentation is loading. Please wait.

Presentation is loading. Please wait.

윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 26. 매크로와 선행처리기.

Similar presentations


Presentation on theme: "윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 26. 매크로와 선행처리기."— Presentation transcript:

1 윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 26. 매크로와 선행처리기

2 윤성우의 열혈 C 프로그래밍 Chapter 선행처리기와 매크로 윤성우 저 열혈강의 C 프로그래밍 개정판

3 선행처리는 컴파일 이전의 처리를 의미합니다. 윤성우의 열혈 C 프로그래밍
일반적으로 컴파일의 과정에 포함이 되어 이야기하지만, 선행처리의 과정과 컴파일의 과정은 구분이 된다.

4 선행처리기의 일 간단히 맛보기 윤성우의 열혈 C 프로그래밍 #define PI 3.14 가 의미하는 바는 다음과 같다.
컴파일러에 비해서 선행처리기의 역할은 매우 간단하다. 쉽게 말해서 ‘단순한 치환’의 작업을 거친다. 그리고 선행처리기에게 무엇인가를 명령하는 문장은 #으로 시작한다.

5 윤성우의 열혈 C 프로그래밍 Chapter 대표적인 선행처리 명령문 윤성우 저 열혈강의 C 프로그래밍 개정판

6 #define: Object-like macro
윤성우의 열혈 C 프로그래밍 #define: Object-like macro PI를 로 무조건 치환하라! printf(“이름: %s \n”, “홍길동”); printf(“나이: %d \n”, 24); puts(“주소: 경기도 용인시 \n”); 치환된 결과물! 실제 컴파일 되는 문장들! 실행결과

7 #define: Function-like macro
윤성우의 열혈 C 프로그래밍 #define: Function-like macro SQUARE(123); SQUARE(NUM); 123*123; NUM*NUM; 이러한 변환의 과정을 가리켜 ‘매크로 확장(macro expansion)’이라 한다. SQUARE(X) 패턴에 부합! 따라서 치환!

8 윤성우의 열혈 C 프로그래밍 매크로 확장의 예 3과 2의 합인 5가 SQUARE 함수의 인자가 되어,. 25가 출력되는 것이 상식적이다! 그러나 출력결과는 다르다! 실행결과

9 잘못된 매크로의 정의와 소괄호의 해결책 윤성우의 열혈 C 프로그래밍 #define SQUARE(X) X*X
오류의 원인 SQUARE((3+2)) (3+2)*(3+2) 사용하기 불편 #define SQUARE(X) (X)*(X) SQUARE(3+2) ( 3+2)*(3+2) 이 경우는 해결 num=120/SQUARE(2) / (2)*(2) 여전히 문제! #define SQUARE(X) ((X)*(X)) num=120/SQUARE(2) / ((2)*(2)) 최상의 해결책!

10 매크로를 두 줄에 걸쳐서 정의하는 방법 윤성우의 열혈 C 프로그래밍 #define SQUARE(X) ((X)*(X))
이렇듯 두 줄에 걸쳐서 매크로를 정의하면 에러가 발생한다! #define SQUARE(X) \ ((X)*(X)) 첫 번째 줄의 끝에 \을 삽입하면 에러가 발생하지 않는다. 이는 \이 매크로의 정의가 이어짐을 뜻하기 때문이다.

11 먼저 정의된 매크로의 사용 윤성우의 열혈 C 프로그래밍
실행결과 위 예제에서 보이듯이, 앞 줄에서 먼저 정의된 매크로는 새로운 매크로를 정의하는데 있어서 사용될 수 있다.

12 일반함수와 비교한 매크로 함수의 장점 장점 1. 장점 2. 윤성우의 열혈 C 프로그래밍
매크로 함수는 일반 함수에 비해 실행속도가 빠르다. 함수의 호출을 완성하기 위해서는 별도의 메모리 공간이 필요하고 호출된 함수로의 이동 및 반환의 과정을 거쳐야 한다. 반면 매크로 함수는 정의된 몸체로 치환이 이뤄지니 이러한 일이 불필요하며, 때문에 실행속도가 빨라질 수 밖에 없다. 장점 2. 자료형에 따라서 별도로 함수를 정의하지 않아도 된다. 전달되는 인자의 자료형에 구분을 받지 않으므로 자료형에 의존적이지 않다.

13 선행처리 후 컴파일러에 의해서 에러가 감지되므로
윤성우의 열혈 C 프로그래밍 매크로 함수의 단점 단점 1. 정의하기가 정말로 까다롭다. 2. 디버깅하기가 쉽지 않다. 선행처리 후 컴파일러에 의해서 에러가 감지되므로 매크로 함수로 정의하면? 잘못 정의된 매크로 그러나 컴파일러는 컴파일 된 이후의 내용을 기준으로 오류를 이야기한다.

14 함수를 매크로로 정의하기 위한 조건 조건 1. 조건 2. 윤성우의 열혈 C 프로그래밍 작은 크기의 함수
한 두줄 정도 크기의 작은 함수가 아니면 매크로로 정의하는 것이 쉽지 않아서 오류발생 확률이 높아진다. 그리고 if~else, for와 같이 실행의 흐름을 컨트롤 하는 문장도 매크로로 정의하기 쉽지 않다. 조건 2. 호출의 빈도수가 높은 함수 함수를 매크로로 정의하는 데에는 성능적 측면이 고려된다. 그런데 호출의 빈도수가 높지 않으면 애써 매크로로 함수를 정의하는 수고를 할 이유가 줄어든다.

15 Chapter 26-3. 조건부 컴파일을 위한 매크로
윤성우의 열혈 C 프로그래밍 Chapter 조건부 컴파일을 위한 매크로 윤성우 저 열혈강의 C 프로그래밍 개정판

16 #if . . . #endif : 참이라면 윤성우의 열혈 C 프로그래밍
선행처리 과정에서 ADD가 ‘참’이면 ~endif 까지 컴파일 대상에 포함 선행처리 과정에서 MIN이 ‘참’이면 ~endif 까지 컴파일 대상에 포함 실행결과

17 #ifdef . . . #endif : 정의되었다면 윤성우의 열혈 C 프로그래밍
ADD와 MIN의 정의 여부만 중요한 상황이라면 각각의 매크로에 값을 지정할 필요가 없다. 즉, 다음과 같이 정의해도 된다. #define ADD #define MIN ADD가 정의되었다면 ~endif 까지 컴파일 대상에 포함 MIN이 정의되었다면 ~endif 까지 컴파일 대상에 포함 실행결과

18 #ifndef . . . #endif : 정의되지 않았다면
윤성우의 열혈 C 프로그래밍 #ifndef #endif : 정의되지 않았다면 ADD가 정의되지 않았다면 ~endif 까지 컴파일 대상에 포함 #ifndef ADD printf("%d + %d = %d \n", num1, num2, num1+num2); #endif #ifndef MIN printf("%d - %d = %d \n", num1, num2, num1-num2); MIN이 정의되지 않았다면 ~endif 까지 컴파일 대상에 포함

19 #else의 삽입: #if, #ifdef, #ifndef에 해당
윤성우의 열혈 C 프로그래밍 #else의 삽입: #if, #ifdef, #ifndef에 해당 포함 조건 매크로 HIT_NUM이 5가 아닐 경우 포함되는 문장 실행결과 #else를 추가해서 조건이 ‘참’이 아닌 경우에 컴파일의 대상에 포함시킬 문장들을 구성할 수 있다.

20 #elif의 삽입: #if에만 해당 윤성우의 열혈 C 프로그래밍
조건에 따라서 이중에서 하나의 문장만 컴파일의 대상으로 포함이 된다. 실행결과 #elif와 #else를 추가해서 if ~ else if ~ else 구문과 동일한 형태를 구성할 수 있다.

21 Chapter 26-4. 매개변수의 결합과 문자열화
윤성우의 열혈 C 프로그래밍 Chapter 매개변수의 결합과 문자열화 윤성우 저 열혈강의 C 프로그래밍 개정판

22 문자열 내에서는 매크로의 매개변수 치환 불가 윤성우의 열혈 C 프로그래밍
[문자열 치환을 목적으로 정의된 매크로] #define STRING_JOB(A, B) "A의 직업은 B입니다." 치환의 대상이 되는 A와 B가 문자열 안에 존재함에 주목하자! [매크로의 확장 결과] STRING_JOB(이동춘, 나무꾼) STRING_JOB(한상순, 사냥꾼) "A의 직업은 B입니다." 이동춘과 나무꾼, 그리고 한상순과 사냥꾼이 기대대로 치환되지 않았다. 문자열 안에서는 치환이 일어나지 않기 때문이다. 이럴 때 고려해 볼 수 있는 연산자가 # 연산자이다!

23 문자열 내에서 매크로 매개변수 치환: # 연산자
윤성우의 열혈 C 프로그래밍 문자열 내에서 매크로 매개변수 치환: # 연산자 [# 연산자를 이용해서 정의된 매크로] #define STR(ABC) #ABC 매개변수 ABC에 전달되는 인자를 문자열 “ABC”로 치환해라! [# 연산자 기반의 매크로 확장 결과] STR(123) STR(12, 23, 34) "123" "12, 23, 34"

24 # 연산자를 이용한 문제의 해결! 윤성우의 열혈 C 프로그래밍
다음 문장 선언은 char * str="ABC" "DEF"; 다음의 문장 선언과 같음과 char * str="ABCDEF“ # 연산자를 근거로 하여 앞서 제시한 문제를 해결한 결과 둘 이상의 문자열 선언을 나란히 하면, 이는 하나의 문자열 선언으로 인식이 된다. 실행결과

25 매크로 연산자 없이 단순 연결은 불가능 윤성우의 열혈 C 프로그래밍 #define STNUM(Y, S, P) YSP
세 개의 숫자를 단순 연결하여 학번을 구성해야 한다고 가정해 보자. 그리고 이를 위한 매크로를 정의해 보자. 치환 대상 YSP를 연결해 놓으면 이는 그냥 YSP로 인식이 된다. #define STNUM(Y, S, P) YSP 치환은 제대로 이뤄지나 Y와 S와 P가 연결되어 있지 않아서 와 같이 치환이 이뤄진다. #define STNUM(Y, S, P) Y S P #define STNUM(Y, S, P) ((Y)* (S)*1000+(P)) ## 연산자를 모르는 상태에서의 최선의 해결책!

26 단순 연결 관련 예제 기반 문제점 확인 윤성우의 열혈 C 프로그래밍
실행결과 실행결과를 보면 로 치환이 이뤄지지 않았음을 알 수 있다. 이는 075가 8진수로 해석된 결과이다. 따라서 이 경우에는 다음과 같이 문장을 구성해야 한다. printf("학번: %d \n", STNUM(10, 65, 75)); 위 예제에서 보이는 매크로도 좋은 해결책이 되지 못한다. 필요한 것은 ‘단순 연결’인데, 8진수 인식의 문제로 인해서 생각할 요소가 발생하기 때문이다! 이는 매크로 STNUM의 사용에 있어서 주의를 요하는 요소가 되므로 좋은 매크로 정의라 할 수 없다!

27 필요한 형태대로 단순 결합: ## 연산자 윤성우의 열혈 C 프로그래밍
[##연산자를 이용해서 정의된 매크로] #define CON(UPP, LOW) UPP ## 00 ## LOW 매개변수 UPP와 LOW에 달되는 인자를 UPP00LOW로 단순히 연결해서 치환해라! [## 연산자 기반의 매크로 확장 결과] 220077 int num = CON(22, 77); 이렇듯 ## 연산자를 이용해서 다음과 같이 매크로를 정의해야 학번을 단순치환 할 수 있다. #define STNUM(Y, S, P) Y ## S ## P

28 Chapter 26이 끝났습니다. 질문 있으신지요?


Download ppt "윤성우의 열혈 C 프로그래밍 윤성우 저 열혈강의 C 프로그래밍 개정판 Chapter 26. 매크로와 선행처리기."

Similar presentations


Ads by Google