C Language 전처리기 (Preprocessor) Doo-ok Seo clickseo@gmail.com http://
목 차 전처리기 조건및분할컴파일 2
전처리기 전처리기 전처리기의기본개념 #include 문 #define 문 조건및분할컴파일 3
C 컴파일러 전처리기의기본개념 전처리기 (Preprocessor) 번역기 (Translator) 전처리는컴파일러가동작하기전단계에서작업이이루어진다. 4
전처리기의기본개념 (cont d) 전처리 (Preprocessing) 원시소스파일을컴파일하기전에행해야할일련의작업 외부파일포함 #include 문에의한외부파일포함기능 매크로상수정의 #define 문에의한매크로상수정의기능 조건부컴파일 (conditional compile) 시스템내장매크로사용 5
전처리기의기본개념 (cont d) 전처리지시자사용시주의사항 전처리의정의는반드시 # 으로시작 # 앞에는공백문자를제외한다른문자가올수없다. 일반적인 C 언어구문과는다르게취급하므로명령어끝에 ; 을 붙이지않는다. 전처리지시문은일반적으로한행에작성한다. 두행이상작성해야할경우는 \ 을사용 6
전처리기의기본개념 (cont d) 프로그램예제 : 전처리개념적용예 #include <stdio.h> #define PI 3.14159 int main() { double // 매크로상수 radius; # 전처리사용시 프로그램수정용이전체적인프로그램구조의간결성유지 printf(" 원의반지름을입력하세요 : "); scanf("%lf", &radius); printf("\n 원의면적 %.2f\n", radius * radius * PI); return 0; 7
#include #include 문 외부의헤더파일 (.h) 에정의된내용을현재프로그램의내부로 포함시키는역할 #include < 시스템정의파일명 > #include 사용자정의파일명 8
#include (cont d) #include 문 (cont d) #include 의간단한사용예 #include <stdio.h> #include <stdlib.h> #include test.h #include c:\clickseo\test.h // 단, 절대경로의사용은좋은습관이아니다. #include /home/clickseo/my_c/include/test.h // UNIX 9
#include 문 (cont d) 프로그램예제 : #include 적용예 score.h #define MAX_SIZE 3 // 구조체형데이터정의부분... typedef struct { char name[10]; int kor, eng, math, tot; float ave; SCORE; // 사용자정의함수원형부분... void INPUT(SCORE *); void OUTPUT(SCORE *); 10
#include 문 (cont d) 프로그램예제 : #include 적용예 score.c #include <stdio.h> #include "score.h" void { INPUT(SCORE *p) int i; for(i=0; i<max_size; i++, p++) { printf("\n %d 번째학생성적입력... \n", i+1); printf(" 학생이름 : "); gets(p->name); printf(" 국어점수 : "); scanf("%d", &p->kor); printf(" 영어점수 : "); scanf("%d", &p->eng); printf(" 수학점수 : "); scanf("%d%*c", &p->math); p->tot = p->kor + p->eng + p->math; p->ave = (float)p->tot / 3; void OUTPUT(SCORE *p) { int i; printf("\n \t ### 학생성적 ### \n"); for(i=0; i<max_size; i++, p++) printf("%10s %3d %3d %3d %5d %8.2f \n", p->name, p->kor, p->eng, p->math, p->tot, p->ave); 11
#include 문 (cont d) 프로그램예제 : #include 적용예 main.c #include <stdio.h> #include "score.h" int main() { SCORE stu[max_size]; INPUT(stu); OUTPUT(stu); return 0; 12
#define 매크로지정자 자주사용되는상수값을정의 #define 문 여러줄에걸쳐사용해야할긴문장을하나의짧은문장으로줄여서표현 #define 매크로 _ 상수명 상수 _ 리스트 #define 매크로 _ 함수명 ( 인자 _ 리스트 ) 함수의내용 매크로상수정의 매크로함수정의 13
#define 문 (cont d) 매크로전개 (macro expansion) 매크로함수역시프로그램을컴파일하기전에전처리기에의해정의된코드로치환이일어난다. #define MAX 100 #define ADD(a, b) (a + b) #define MAX 100 #define ADD(a, b) a + b void main() { for(i=0;i<max; i++) { preprocessing (macro expansion) void main() { for (i=0; i<100; i++) { sum = ADD(10, 20); sum = (10 + 20); 적용전 적용후 14
매크로상수 매크로상수정의예 #define 문 (cont d) #define MAX_SIZE 100 // 정수형상수정의 #define PI 3.141592 // 실수형상수정의 #define TITLE Business Control System // 문자열상수정의 #define ALERT Insert more coins if you want to continue the game #define ESC 0x1b // ESC 키에대한 ASCII 코드 #define CR 0x0d // 캐리지리턴 #define LF 0x0a // 라인피드 #define TRUE 1 // Boolean 값 true #define FALSE 0 // Boolean 값 false 15
매크로상수 (cont d) #define 문 (cont d) while (TRUE) { ch = getchar(); if (ch == ESC) break: while (1) { ch = getchar(); if (ch == 0x1b) break; [ 적용전 ] [ 적용후 ] 16
#define 문 (cont d) 매크로상수 (cont d) #define ALERT Please, insert more coins printf( GAME OVER : ALERT n ); // ALERT 는 printf() 의단순문자열일뿐이다. #define YOUR_MONEY 1000 #define MY_MONEY 2000 #define ALL_MONEY (MY_MONEY + YOURMONEY) printf( ALL money : %d n, ALL_MONEY); // 적법 #define ALL_MONEY MY_MONEY + YOUR_MONEY // 주의 : ( ) 생략하면위험!! share = ALL_MONEY / 3; /* share = 1000 + 2000/3 */ 17
매크로함수 매크로함수정의 #define ADD(a, b) (a + b) #define 문 (cont d) 함수의내용 함수의몸체정의 괄호를생략하지않도록주의한다. 인자리스트 일반함수의형식인자와동일단, 자료형을명시하지는않는다. 인자가없을수는있지만괄호를생략할수는없다. 함수명 가급적대문자로작명하여일반함수와구분해주는것이좋다. sum = ADD(x, y); preprocessing (macro expansion) sum = (x + y); 함수호출에따르는시간적부담이적다. 18
#define 문 (cont d) 매크로함수 (cont d) 매크로함수사용예 #define MUL(a, b) (a * b) int x=10, y=20; printf( %d n, MUL(x, y)); // 1 : 정확한값출력 : 200 == (10 * 20) printf( %d n, MUL(x+10, y)); // 2 : 잘못된결과출력 : 210 == (10 + 10 * 20) MUL(x+10, y) == (10 + 10 * 20) // 연산자우선순위에의해결과는 210 이된다. #define MUL(a, b) ((a) * (b)) // 매개변수는가급적괄호로묶는다. MUL(x+10, y) == ((10 + 10) * 20) // 의도했던 400 이산출된다. #define MUL (a, b) ((a) * (b)) // Error!! : 함수명과인자리스트사이의공백은불허 19
매크로함수 (cont d) #define 문 (cont d) C 언어는문자열상수를이어서선언할수있다. #include <stdio.h> int main() { char *str = "AAA" "BBB"; // char *str = AAABBB puts(str); puts("eee" "FFF"); return 0; 20
#define 문 (cont d) 매크로함수 (cont d) 매크로에의환치환은문자열내에서는이루어지지않는다. #include <stdio.h> #define ADD(x, y) printf("x + y = %d \n", x + y) int main() { ADD(3, 4); return 0; 21
매크로함수 (cont d) #define 문 (cont d) # : 매크로함수전달인자의문자열화 #define PRINT(expr) printf(#expr = = %d, expr) PRINT(3 * 5); 의경우 printf( 3 * 5 = %d, 3 * 5); 와같이전개된다음 printf( 3 * 5 = %d, 3 * 5); 로최종해석된다. 결과적으로 3 * 5 = 15 가화면에출력된다. #include <stdio.h> #define ADD(x, y) printf(#x "+" #y "=%d \n", x + y) int main() { ADD(3, 4); return 0; 22
매크로함수 (cont d) #define 문 (cont d) ## : 토큰을결합할때사용 토큰 (token) 컴파일러가인식하는의미를지니는문자나문자열의최소단위 용도 : 변수나함수의이름을동적으로작성하기위하여사용된다. #define CAT(x,y) x##y y = CAT(temp, Value); 의경우y = tempvalue; 와같이전개된다. tempvalue 변수의값이 10이라면결과적으로 y = 10 과같다. 23
매크로함수 (cont d) 장 / 단점 #define 문 (cont d) 매크로함수의실행속도가일반함수보다조금빠르다. 매크로함수는매개변수와반환값의데이터형을정의할필요가없다. 매크로함수는컴파일전에정의된코드로치환 매크로함수가여러곳에서많이사용되면컴파일속도가느려진다. 매크로함수는 3 ~ 4 행을넘지않는간단한함수정의에적합하다. 매크로함수사용시주의사항 매크로함수를정의할때함수의내용전체와내부에서사용된매개변수는괄호로묶어서혼돈이없도록해야한다. 매크로함수명과매개변수리스트왼쪽괄호사이에공백이오면안된다. 매크로함수명은가급적대문자를사용하여일반함수와구분 24
조건및분할컴파일 전처리기 조건및분할컴파일 조건컴파일 분할컴파일 시스템내장매크로 25
조건컴파일 조건컴파일 (conditional compile) 특정조건을만족할경우에지정한범위내의문장을컴파일 #if, #ifdef, #ifndef, #else, #elif, #endif, #if defined, #if!defined 조건컴파일지시자사용형식 #if 상수식1 실행문장영역1 #elif 상수식2 실행문장영역2 #else 실행문장영역n #endif #ifdef 매크로명실행문장영역1 #elif 상수식1 실행문장영역2 #else 실행문장영역n #endif #ifndef 매크로명실행문장영역1 #elif 상수식1 실행문장영역2 #else 실행문장영역n #endif { 를사용하지않기때문에 #endif 생략불가 ++, --, &, * 와기타복합연산자사용제한 #ifdef 와 #ifndef는 #if defined( 매크로명 ), #if!defined( 매크로명 ) 26
조건컴파일 (cont d) 사용예 조건컴파일 (cont d) #if defined(init_system) && defined(menu_system) #if SYSTEM_MEMORY >= 512 #define MAX_PROCESS 100 #elif SYSTEM_MEMORY <= 512 #define MAX_PROCESS 50 #else #define MAX_PROCESS 10 #endif if (pcount >= MAX_PROCESS) { printf( All process are assigned. n ); 27
조건컴파일 (cont d) 조건컴파일 (cont d) 사용예 ( 헤더파일중복방지 ) #ifndef INIT_GAME_H // INIT_GAME_H 가정의되지않았으면... #define INIT_GAME_H // INIT_GAME_H 를정의하고... 헤더의내용 // #endif 전까지의내용이인식된다. #endif #ifdef INIT_GAME_H // INIT_GAME_H 가정의되어있다면... #include menu.h // menu.h 파일을포함하고... #else // 그렇지않으면... #include init.h // init.h 파일을포함하라는뜻 #endif 28
조건컴파일 (cont d) 프로그램예제 : #if, #else, #elif, #endif 지시문의사용예 #include <stdio.h> #include <conio.h> #define TRUE 1 #define FALSE 0 #define CONDITION TRUE #define EQ == int main() { #if CONDITION EQ TRUE puts("condition is TRUE"); puts(" 1 == 1 "); #elif CONDITION EQ FALSE puts("condition is FALSE"); puts(" 0 == 0 "); #else puts("condition is etc"); puts(" etc == etc "); #endif return 0; 29
프로그램예제 : #ifdef, #ifndef 지시문의사용예 #include <stdio.h> #define DEBUG void func(int a, int b) { int c; c = (a+1) * (b+2); 조건컴파일 (cont d) #ifdef #endif DEBUG printf("i=%d, j=%d, c=%d \n", a, b, c); int main(void) { int i=0, j=0; #ifndef DEBUG printf("i=%d, j=%d \n", i, j); #endif i=3, j=5; func(i, j); return 0; 30
조건컴파일 (cont d) #undef 문 조건컴파일 (cont d) 이미정의된매크로기능을없던일로되돌린다. 사용형식 #undef macro_name 간단한사용예 #ifdef TITLE #undef TITLE #endif #define TITLE COMPUTER SCIENCE 31
프로그램예제 : #undef 지시문의사용예 #include <stdio.h> #include <conio.h> 조건컴파일 (cont d) #definesize 100 #define PRINT(data) printf("%d\n", data); int main(void) { int a, b, c; a = SIZE; #ifdef SIZE #undef SIZE #endif #definesize 200 b = SIZE; #ifdef SIZE #undef SIZE #endif #definesize 300 c = SIZE; PRINT(a); PRINT(b); PRINT(c); return 0; 32
조건컴파일 (cont d) #error 문 조건컴파일 (cont d) 오류가발생할경우오류메시지를출력하기위한용도로사용 #error 문을만나면컴파일을즉시중단하고, 시스템에서미리정의한오류메시지의일부로 errmsg를포함하여출력한다. 사용형식 #error errmsg 간단한사용예 #if REQUIRED_MEMORY > 128 #else #error OOPs! This program can be used with 128 RAM #endif 33
조건컴파일 (cont d) #line 문 조건컴파일 (cont d) 현재컴파일되고있는프로그램의행번호와파일명을변경하고자할때사용한다. 사용형식 #line line-num filename 간단한사용예 #line 1000 watch.c /* 다음라인을 1001 번라인으로파일명은 watch.c 로설정 */ #error see this error message 에러가자주발생하는영역 34
조건컴파일 (cont d) #pragma 문 조건컴파일 (cont d) 컴파일러에게특수한기능이나동작을수행하게끔지시하는용도 간단한사용예 #pragma warn -rvl // Function should return a value 경고를발생하지못하게한다. #pragma warn +cln // long 형상수에접미사 L 을붙이지않으면경고를발생케한다. 주의 : 컴파일러의종류에따라용법에차이가있다. 35
단일컴파일환경 분할컴파일 36
분할컴파일환경 분할컴파일 (cont d) 37
분할컴파일 extern 으로선언되어야다른모듈에서사용될수있다. 분할컴파일 (cont d) login.h #ifndef LOGIN_H #define LOGIN_H #define LOGIN_ID "root" #define ROOT_PASS clickt" extern char userid[10]; extern char password[10]; extern char *username; extern int login(void); #endif main.h #ifndef MAIN_H #define MAIN_H #define DEBUG_MODE #define TRUE 1 #define FALSE 0 #define ESC 0x1b #define ALERT(msg) #define CONT_MSG #define UNAUTH_MSG #endif #ifndef SERVICE_H #define SERVICE_H extern void doservice(void); #endif service.h #include main.h ; #include login.h ; char userid[10]={0,; char password[10]={0,; char *username="go Gil Dong"; int login() { main.h 의 TRUE, FALSE 사용 login.c #include main.h ; #include login.h ; #include service.h ; int main() { found = login(); if (found) doservice(); test.c 사용하고자하는변수나함수가들어있는헤더파일을 incldue한다. #include login.h ; #include service.h ; int doservice() { login.h 의 userid, username, password 사용 service.c 링킹 login.obj + test.obj + srvice.obj test.exe 38
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 main.h #ifndef MAIN_H #define MAIN_H #define DEBUG_MODE #define TRUE 1 #define FALSE 0 #define ESC 0x1b #define ALERT(msg) printf("%s\n",msg) #define CONT_MSG "Press any key to retry, or press ESC to quit.\n" #define UNAUTH_MSG "Error: OOps! Unauthorized Access...\n" #endif 39
프로그램예제 : 조건및분할컴파일예제 main.c (1/2) #include <stdio.h> #include <conio.h> #include main.h #include login.h #include service.h 분할컴파일 (cont d) int main() { int ch, found = 0; while (TRUE) { found = login(); if (found) { doservice(); break; 40
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 main.c (2/2) else { printf("error: OOps! Unauthorized Access...\n"); #if defined(debug_mode) printf("login ID = %s, password = %s, \n", LOGIN_ID, ROOT_PASS); printf("don't forget it anymore...\n"); #endif ALERT(CONT_MSG); ch = getch(); if (ch == ESC) break; return 0; 41
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 login.h #ifndef LOGIN_H #define LOGIN_H #define LOGIN_ID root #define ROOT_PASS clickseo extern char extern char extern char extern int #endif userid[10]; password[10]; *username; login(void); 42
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 login.c #include <stdio.h> #include <string.h> #include main.h #include login.h char userid[10] = {0,; char password[10] = {0,; char *username = Seo Doo Ok"; int login(void) { printf("> login ID : "); scanf("%s", userid); printf("> password : "); scanf("%s", password); if (!strcmp(userid,"root") &&!strcmp(password, ROOT_PASS)) return TRUE; else return FALSE; 43
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 service.h #ifndef SERVICE_H #define SERVICE_H extern void doservice(void); #endif 44
분할컴파일 (cont d) 프로그램예제 : 조건및분할컴파일예제 service.c #include <stdio.h> #include main.h #include login.h #include service.h void doservice(void) { int n; printf("<<<<<<<<<<<< USER SERVICE >>>>>>>>>>>>>>>\n"); printf("welcome Back, %s\n", username); printf("your id=%s, pw=%s\n", userid, password); do { printf("which service do you want? \n"); printf("1. Change password\n"); printf("2. Let me know about...\n"); printf("3. Could you tell me...\n"); printf("4. Quit\n"); scanf("%d", &n); while (n!=4); 45
시스템내장매크로 시스템내장매크로 시스템에서제공하는미리내장된매크로 시스템내장매크로 STDC FILE LINE DATE TIME TIMESTAMP 컴파일러의 ANSI C 표준준수여부 (1 이면준수 ) 현재컴파일되고있는파일의이름 현재컴파일되고있는프로그램의행번호 컴파일날짜 ( 월, 일, 년 ) 컴파일이시작된시간 ( 시 : 분 : 초 ) 컴파일이시작된날짜와시간 46
프로그램예제 : 시스템내장매크로사용예 #1 #include <stdio.h> 시스템내장매크로 (cont d) int main() { printf("compile Information: %s, line: %d, on %s, at %s\n", FILE, LINE, DATE, TIME ); #line 1000 "seethis.c" printf("changed compile Information\n"); printf("compile Information: %s, line: %d, on %s, at %s\n", FILE, LINE, DATE, TIME ); return 0; 47
프로그램예제 : 시스템내장매크로사용예 #2 #include <stdio.h> 시스템내장매크로 (cont d) int main(void) { printf(" 현재컴파일되고있는날짜 : %s\n", DATE ); printf(" 현재컴파일되고있는시간 : %s\n", TIME ); printf(" 현재컴파일되고있는날짜와시간 : %s\n", TIMESTAMP ); printf(" 파일명 : %s\n", FILE ); printf(" 현재라인 : %d\n", LINE ); #ifdef STDC printf(" 현재컴파일러는 ANSI 표준 \n"); #else printf(" 현재컴파일러는 ANSI C 표준의확장 \n"); #endif return 0; 48
참고문헌 [1] 김일광저, C 프로그래밍입문, 한빛미디어, pp. 324 354. [2] 윤성우, 열혈강의 C 프로그래밍, 프리렉, pp. 571 635. [3] 김진외 7 인공역, 구조적프로그래밍기법을위한 C, 인터비젼, pp. 966 978. [4] Brian W. Kernighan, Dennis M. Ritchie, The C Programming Language 2/e, 대영사, 317 358. 49