2015-1 11-1. 전처리기, 다중소스파일 2015 년 5 월 11 일 교수김영탁 영남대학교공과대학정보통신공학과 (Tel : +82-53-810-2497; Fax : +82-53-810-4742 http://antl.yu.ac.kr/; E-mail : ytkim@yu.ac.kr)
Outline 전처리기 (preprocessor) 다중소스파일 헤더파일 함수소스파일 main() 함수소스파일 ch11-1 - 2
전처리기란? 전처리기 (preprocessor) 는컴파일하기에앞서서소스파일을처리하는컴파일러의한부분 #include, #define 만처리합니다. 수고했어, 나머지는나한테맡겨! 소스파일 임시파일 오브젝트파일 전처리기 컴파일러 ch11-1 - 3
전처리기의요약 지시어 #define #include #undef #if #else #endif #ifdef #ifndef #line #pragma 의미매크로정의파일포함매크로정의해제조건이참일경우조건이거짓일경우조건처리문장종료매크로가정의되어있는경우매크로가정의되어있지않은경우행번호출력시스템에따라의미가다름
단순매크로 단순매크로 (macro): 숫자상수를기호상수로만든것 ( 예 ) #define MAX_SIZE 100 #define PI 3.141592 #define EPS 1.0e-9 // epsilon 100 보다는 MAX_SIZE 가이해하기쉽지.. ch11-1 - 5
단순매크로 #define MAX_SIZE 100... while(i<max_size) { sum += i; i++; }... 전처리기... while(i<100) { sum += i; i++; }... ch11-1 - 6
단순매크로의장점 프로그램의가독성을높인다. 상수의변경이용이하다. 기호상수를사용하는경우 숫자를사용하는경우 ch11-1 - 7
단순매크로의예 #define PI 3.141592 // 원주율 #define TWOPI (3.141592 * 2.0) // 원주율의 2배 #define MAX_INT 2147483647 // 최대정수 #define EOF (-1) // 파일의끝표시 #define MAX_STUDENTS 2000 // 최대학생수 #define EPS 1.0e-9 // 실수의계산한계 #define DIGITS "0123456789" // 문자상수정의 #define BRACKET "(){}[]" // 문자상수정의 #define getchar() getc(stdin) // stdio.h에정의 #define putchar() putc(stdout) // stdio.h에정의 2147483647 보다는 MAX_INT 가낫죠 사람은숫자보다기호를잘기억합니다. ch11-1 - 8
예제 #include <stdio.h> #define AND && #define OR #define NOT! #define IS == #define ISNOT!= C 프로그램을다른언어처럼작성할수있습니다. int search(int list[], int n, int key) { int i= 0; && } while( i < n AND list[i]!= key ) i++; if( i IS n ) return -1; == else return i; ch11-1 - 9
함수매크로 함수매크로 (function-like macro) 란매크로가함수처럼매개변수를가지는것 ( 예 ) #define SQUARE(x) ((x) * (x)) #define SQUARE(x) ((x) * (x)) 전처리기 v = SQUARE(3); v = ((3)*(3)); ch11-1 - 10
함수매크로의예 #define SUM(x, y) ((x) + (y)) #define AVERAGE(x, y, z) (( (x) + (y) + (z) ) / 3 ) #define MAX(x,y) ( (x) > (y) )? (x) : (y) #define MIN(x,y) ( (x) < (y) )? (x) : (y) ch11-1 - 11
주의할점 #define SQUARE(x) x*x // 위험!! v = SQUARE(a+b); v = a + b*a + b; 함수매크로에서는매개변수를괄호로둘러싸는것이좋습니다. #define SQUARE(x) ((x)*(x)) // 올바른형태 ch11-1 - 12
함수매크로의장단점 함수매크로의장단점 함수호출단계가필요없어실행속도가빠르다. 소스코드의길이가길어진다. 간단한기능은매크로를사용 #define MIN(x, y) #define ABS(x) ((x) < (y)? (x) : (y)) ((x) > 0? (x) : -(x)) 매크로를한줄이상연장하는방법 #define PRINT(x) if( debug==1 && mode==1 ) printf( %d, x); ch11-1 - 13
예제 #1 // 매크로예제 #include <stdio.h> #define SQUARE(x) ((x) * (x)) int main(void) { int x = 2; ((++x) * (++x)) printf("%d\n", SQUARE(x)); printf("%d\n", SQUARE(3)); printf("%f\n", SQUARE(1.2)); // 실수에도적용가능 printf("%d\n", SQUARE(x+3)); printf("%d\n", 100/SQUARE(x)); printf("%d\n", SQUARE(++x)); // 논리오류 } return 0; 4 9 1.440000 25 25 16 ch11-1 - 14
# 연산자 PRINT(x) 와같이호출하면와같이출력하는매크로작성 x=5 다음과같이작성하면잘못된결과가나온다. #define PRINT(exp) printf("exp=%d\n", exp); exp=5 ch11-1 - 15
# 은문자열변환연산자 (Stringizing Operator) 라고불린다. 매크로정의에서매개변수앞에 # 가위치하면매크로호출에의하여전달되는실제인수는큰따옴표로감싸지고문자열로변환된다. #define PRINT(exp) printf(#exp" = %d n",exp); PRINT(x); x=5 ch11-1 - 16
## 연산자 ## 연산자는토큰병합연산자 (token-pasting operator) #define MAKE_NAME(n) v ## n MAKE_NAME(1) 과같이호출된다고가정하자. 매개변수 n 은 1 로치환되고 ## 연산자에의하여 v 와 1 이합쳐져서하나의토큰 v1 이된다. ch11-1 - 17
예제 #include <stdio.h> #define MAKE_NAME(n) v ## n #define PRINT(n) printf("v" #n " = %d\n", v ## n); int main(void) { int MAKE_NAME(1) = 10; // v1 = 10 int MAKE_NAME(2) = 20; // v2 = 20 PRINT(1); // printf("v1 = %d\n", v1); 과같다. PRINT(2); // printf("v2 = %d\n", v2); 과같다. return 0; } v1 = 10 v2 = 20 ch11-1 - 18
내장매크로 내장매크로 : 미리정의된매크로 내장매크로 설명 DATE 이매크로를만나면현재의날짜 ( 월일년 ) 로치환된다. TIME 이매크로를만나면현재의시간 ( 시 : 분 : 초 ) 으로치환된다. LINE 이매크로를만나면소스파일에서의현재의라인번호로치환된다. FILE 이매크로를만나면소스파일이름으로치환된다. printf(" 컴파일날짜 =%s\n", DATE ); printf(" 치명적에러발생파일이름 =%s 라인번호 = %d\n", FILE, LINE ); ch11-1 - 19
예제 : ASSERT 매크로 #include <stdio.h> #define ASSERT(exp) { if (!(exp)) \ { printf(" 가정 (" #exp ") 이소스파일 %s %d 번째줄에서실패.\n"\, FILE, LINE ), exit(1);}} int main(void) { int sum; // 지역변수의초기값은 0 이아님 매크로를다음줄로연장할때사용 } ASSERT(sum == 0); // sum 의값은 0 이되어야함. return 0; 가정 (sum == 0) 이소스파일 c:\source\chapter15\macro3\macro3\macro3.c 11 번째줄에서실패. ch11-1 - 20
비트관련매크로 매크로들은변수를받아서특정비트값을반환하거나설정한다. GET_BIT(w, k) 는변수 w 에서 k 번째비트의값을 0 또는 1 로반환한다. #define GET_BIT(w, k) (((w) >> (k)) & 0x01) SET_BIT_ON(w, k) 는변수 w 의 k 번째비트를 1 로설정하는매크로이다. #define SET_BIT_ON(w, k) ((w) = (0x01 << (k))) SET_BIT_OFF(w, k) 는변수 w 의 k 번째비트를 0 로설정하는매크로이다. #define SET_BIT_OFF(w, k) ((w) &= ~(0x01 << (k))) ch11-1 - 21
예제 : ASSERT 매크로 #include <stdio.h> #define GET_BIT(w, k) (((w) >> (k)) & 0x01) #define SET_BIT_ON(w, k) ((w) = (0x01 << (k))) #define SET_BIT_OFF(w, k) ((w) &= ~(0x01 << (k))) int main(void) { int data=0; SET_BIT_ON(data, 2); printf("%08x\n", data); printf("%d\n", GET_BIT(data, 2)); } SET_BIT_OFF(data, 2); printf("%08x\n", data); printf("%d\n", GET_BIT(data, 2)); return 0; 00000004 1 00000000 0 ch11-1 - 22
#ifdef 어떤조건이만족되었을경우에만컴파일하는조건부컴파일지시 #ifdef 매크로문장1 #else 문장2 #endif // 매크로가정의되었을경우 // 매크로가정의되지않았을경우 ch11-1 - 23
#ifdef 의예 ch11-1 - 24
예제 #include <stdio.h> #define LINUX int main(void) { #ifdef LINUX... #else... #endif return 0; } LINUX 버전 WINDOWS 버전 ch11-1 - 25
Visual C++ 에서설정하는방법 ch11-1 - 26
#ifndef #ifndef, #undef 어떤매크로가정의되어있지않으면컴파일에포함된다. #undef 매크로의정의를취소한다 ch11-1 - 27
#if 기호가참으로계산되면컴파일 조건은상수이어야하고논리, 관계연산자사용가능 ch11-1 - 28
#if-#else-#endif ( 예 ) #if NATION == 1 #include "korea.h" #elif NATION == 2 #include "china.h" #else #include "usa.h" #endif ch11-1 - 29
다양한예 조건부컴파일 #if (VERSION > 3)... #endif // 가능! 버전이 3 이상이면컴파일 #if (AUTHOR == KIM) // 가능!! KIM은다른매크로 #if (VERSION*10 > 500 && LEVEL == BASIC) // 가능!! #if (VERSION > 3.0) // 오류!! 버전번호는 300과같은정수로표시 #if (AUTHOR == "CHULSOO") // 오류!! #if (VERSION > 300 defined(deluxe) ) ch11-1 - 30
조건부컴파일을이용하는디버깅 #define DEBUG 1... #if DEBUG == 1 printf(" 현재 counter 의값은 %d 입니다. n", counter); #endif #define DEBUG... #ifdef DEBUG printf(" 현재 counter 의값은 %d 입니다. n", counter); #endif... #if defined(debug) printf(" 현재 counter 의값은 %d 입니다. n", counter); #endif ch11-1 - 31
예제 정렬알고리즘을선택 #define SORT_METHOD 3 #if (SORT_METHOD == 1)... // 선택정렬구현 #elif (SORT_METHOD == 2)... // 버블정렬구현 #else... // 퀵정렬구현 #endif ch11-1 - 32
헤더파일이중포함방지 /** stdio.h - definitions/declarations for standard I/O routines */ #ifndef _INC_STDIO #define _INC_STDIO...... #endif 헤더파일이포함되면매크로가정의되어서이중포함을방지합니다. ch11-1 - 33
다중소스파일 단일소스파일 파일의크기가너무커진다. 소스파일을다시사용하기가어려움 다중소스파일 서로관련된코드만을모아서하나의소스파일로할수있음 소스파일을재사용하기가간편함 ch11-1 - 34
다중소스파일 ch11-1 - 35
예제 multiple_source.c // 다중소스파일 #include <stdio.h> #include "power.h" int main(void) { int x,y; printf("x 의값을입력하시오 :"); scanf("%d", &x); printf("y 의값을입력하시오 :"); scanf("%d", &y); printf("%d 의 %d 제곱값은 %f\n", x, y, power(x, y)); power.h // power.c에대한헤더파일 #ifndef POWER_H #define POWER_H double power(int x, int y); #endif power.c // 다중소스파일 #include "power.h double power(int x, int y) { double result = 1.0; int i; } return 0; for(i = 0;i < y; i++) result *= x; } return result; ch11-1 - 36
헤더파일을사용하지않으면 ch11-1 - 37
헤더파일을사용하면 ch11-1 - 38
다중소스파일에서외부변수 ch11-1 - 39
비주얼 C++ 에서다중소스파일 ch11-1 - 40
비주얼 C++ 에서다중소스파일 ch11-1 - 41
비주얼 C++ 에서다중소스파일 ch11-1 - 42
헤더파일이중포함방지 #include <stdio.h> #include "rect.h" #include "rect.h" 구조체의정의가이중으로포함되어서오류가발생한다. #define DEBUG void draw_rect(const RECT *r) { #ifdef DEBUG printf("draw_area(x=%d, y=%d, w=%d, h=%d) \n", r->x, r->y, r->w, r->h); #endif } ch11-1 - 43
헤더파일이중포함방지 #ifndef RECT_H #define RECT_H struct rect { int x, y, w, h; }; RECT_H 가정의되어있지않은경우에만포함시킨다. RECT_H 매크로를정의한다. typedef struct rect RECT; void draw_rect(const RECT *); double calc_area(const RECT *); void move_rect(rect *, int, int); #endif ch11-1 - 44
Homework 11-1 11-1.1 프로그램작성에서헤더파일을별도로작성하는필요성에대하여설명하라. 11-1.2 조건부컴파일을사용하여, test scenario별로별도의시험조건으로프로그램을실행시키는방법을예를들어설명하라. ch11-1 - 45