제 15 장전처리및비트연산 유준범 (JUNBEOM YOO) Ver. 2.0 jbyoo@konkuk.ac.kr http://dslab.konkuk.ac.kr 본강의자료는생능출판사의 PPT 강의자료 를기반으로제작되었습니다.
이번장에서학습할내용 전처리기란무엇인가? 단수매크로 함수매크로 내장매크로 다중소스파일 비트단위연산자 전처리기를사용하면복잡한컴파일을쉽게할수있습니다. 2
mile2km.c #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { double mile, km; if( argc!= 2 ){ printf(" 사용방법 : mile2km 거리 \n"); return 1; } mile = atof(argv[1]); km = 1.609 * mile; printf(" 입력된거리는 %f km 입니다. \n", km); } return 0; Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. c:\cprogram\mainarg\debug>mainarg 10 입력된거리는 16.090000 km 입니다. c:\cprogram\mainarg\debug> 3
전처리기란? 전처리기 (preprocessor) 는컴파일하기에앞서서소스파일을처리하는컴파일러의한부분 #include, #define,.. 만처리합니다. 수고했어, 나머지는나한테맡겨 소스소스파일 임시임시파일 오브젝트파일파일 전처리기 컴파일러 4
전처리기의요약 지시어 #define #include #undef #if #else #endif #ifdef #ifndef #line #pragma 의미매크로정의파일포함매크로정의해제조건이참일경우조건이거짓일경우조건처리문장종료매크로가정의되어있는경우매크로가정의되어있지않은경우행번호출력시스템에따라의미가다름 5
단순매크로 단순매크로 (macro): 숫자상수를기호상수로만든것 #define 매크로치환텍스트 ( 예 ) #define MAX_SIZE 100 #define #define MAX_SIZE MAX_SIZE 100 100 While(i<MAX_SIZE) While(i<MAX_SIZE) { sum sum += += i; i; i++; i++; } While(i<100) While(i<100) { sum sum += += i; i; i++; i++; } 전처리기 6
단순매크로의장점 프로그램의가독성을높인다. 상수의변경이용이하다. #define #define MAX_SIZE MAX_SIZE 100 100 for(i=0;i<max_size;i++) for(i=0;i<max_size;i++) { { f f += += (float) (float) i/max_size; i/max_size; } } for(i=0;i<100;i++) for(i=0;i<100;i++) { f += += (float) (float) i/100; i/100; } #define #define MAX_SIZE MAX_SIZE 1000 1000 for(i=0;i<max_size;i++) for(i=0;i<max_size;i++) { { f f += += (float) (float) i/max_size; i/max_size; } } 기호상수를사용하는경우 for(i=0;i<1000;i++) for(i=0;i<1000;i++) { f += += (float) (float) i/1000; i/1000; } 숫자를사용하는경우 7
단순매크로의예 #define PRINT printf #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에정의 214748364 7 보다는 MAX_INT 가낫죠 사람은숫자보다기호를잘기억합니다. 8
예제 #1 #include <stdio.h> #define AND && #define OR #define NOT! #define IS == #define ISNOT!= int search(int list[], int n, int key) { int i= 0; C 프로그램을다른언어처럼작성할수있습니다. while( i < n AND list[i]!= key ) i++; if( i IS n ) return -1; else return i; } int main(void) { int m[] = { 1, 2, 3, 4, 5, 6, 7 }; } printf("%d\n", search(m, sizeof(m)/sizeof(m[0]), 5)); return 0; 9
함수매크로 함수매크로 (function-like macro) 란매크로가함수처럼매개변수를가지는것 #define 매크로 ( 매개변수 1, 매개변수 2,) 치환텍스트 ( 예 ) #define SQUARE(x) ((x) * (x)) 전처리기 #define SQUARE(x) ((x) * (x)) v = SQUARE(3); v = ((3)*(3)); 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) #define SQUARE(x) x*x // 위험!! v = SQUARE(a+b); v = a + b*a + b; 함수매크로에서는매개변수를괄호로둘러싸는것이좋습니다. 11
예제 #1 1. // 매크로예제 2. #include <stdio.h> 3. #define SQUARE(x) ((x) * (x)) 4. 5. int main(void) 6. { ((++x) * (++x)) 7. int x = 2; 8. 9. printf("%d\n", SQUARE(x)); 10. printf("%d\n", SQUARE(3)); 11. printf("%f\n", SQUARE(1.2)); // 실수에도적용가능 12. printf("%d\n", SQUARE(x+3)); 13. printf("%d\n", 100/SQUARE(x)); 14. printf("%d\n", SQUARE(++x)); // 논리오류 15. 16. return 0; 17. } 4 9 1.440000 25 25 16 12
함수매크로의장단점 함수매크로의장단점 함수호출단계가필요없어실행속도가빠르다. 소스코드의길이가길어진다. 간단한기능은매크로를사용 #define MIN(x, y)((x) < (y)? (x) : (y)) #define ABS(x) ((x) > 0? (x) : -(x)) 13
내장매크로 내장매크로 : 미리정의된매크로 내장매크로 설명 DATE 이매크로를만나면현재의날짜 ( 월일년 ) 로치환된다. TIME 이매크로를만나면현재의시간 ( 시 : 분 : 초 ) 으로치환된다. LINE 이매크로를만나면소스파일에서의현재의라인번호로치환된다. FILE 이매크로를만나면소스파일이름으로치환된다. 예 ) printf(" 컴파일날짜 =%s\n", DATE ); printf(" 치명적에러발생파일이름 =%s 라인번호 = %d\n", FILE, LINE ); 14
예제 : ASSERT 매크로 1. #include <stdio.h> 2. #define DEBUG 3. #ifdef DEBUG 4. #define ASSERT(exp) { if (!(exp)) \ 5. { printf(" 가정 (" #exp ") 이소스파일 %s %d번째줄에서실패.\n"\ 6., FILE, LINE ), exit(1);}} 7. #else 8. #define ASSERT(exp) 9. #endif 10. int main(void) 11. { 12. int sum; // 지역변수의초기값은 0이아님 매크로를다음줄로연장할때사용 13. ASSERT(sum == 0); // sum의값은0이되어야함. 14. return 0; 15. } 가정 (sum == 0) 이소스파일 c:\cprogram\test\test.c 17 번째줄에서실패. 15
#ifdef 조건부컴파일을지시 어떤조건이만족되었을경우에만컴파일 #ifdef 매크로문장1 // 매크로가정의되었을경우 #else 문장2 // 매크로가정의되지않았을경우 #endif ( 예 ) #define LINUX // 매크로정의 #ifdef LINUX // 리눅스버전에관련된문장들 #else // 윈도우버전에관련된문장들 #endif // 공통적으로필요한문장들 리눅스리눅스버전버전 윈도우윈도우버전버전 공통공통부분부분 16
#if 기호가참으로계산되면컴파일 조건은상수이어야하고논리, 관계연산자사용가능 #if 조건문장들 #endif #define METHOD 1 #if METHOD == 1 printf(" 방법 1 이선택되었습니다.\n"); #endif #if 조건 1 문장 1 #elif 조건 2 문장 2 #else 문장 3 #endif else if 를줄인것 17
다양한예 #if (VERSION > 3) #endif #if (VERSION > 3.0) // 버전이 3 이상이면컴파일 // 오류!! 버전번호는 300 과같은정수로표시 #if (AUTHOR == "CHULSOO") // 오류!! #if (AUTHOR == KIM) // 가능!! KIM 은다른매크로 #if (VERSION*10 > 500 && LEVEL == BASIC) // 가능!! #if (VERSION > 300 defined(deluxe) ) #if 0 #endif // 소스의일부분을주석처리하는방법 18
조건부컴파일을이용하는디버깅 #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 19
헤더파일이중포함방지 /*** *stdio.h - definitions/declarations for standard I/O routines ****/ #ifndef _INC_STDIO #define _INC_STDIO.. #endif 헤더파일이포함되면매크로가정의되어서이중포함을방지합니다. 20
#undef, #pragma #undef: 매크로의정의를취소 1. #include <stdio.h> 2. #define DEBUG 3. int main(void) 4. { 5. #ifdef DEBUG 6. printf("debug이정의되었습니다.\n"); 7. #endif 8. #undef DEBUG // DEBUG 매크로의정의를취소 9. #ifdef DEBUG 10. printf("debug이정의되었습니다.\n"); // 컴파일되지않는다. 11. #endif 12. return 0; 13. } 21
#include 지정된파일을읽어서그위치에삽입 #include <..> 표준디렉토리에서파일을찾는다. #include.. 현재디렉토리에서파일을찾는다. 표준디렉토리 INCLUDE라는환경변수가지정하는디렉토리이다. 보통은 C:\Program Files\Microsoft Visual Studio\VC98\include 하부디렉토리를지정할수있다. #include "graphic/point.h" 22
다중소스파일 단일소스파일 파일의크기가너무커진다. 소스파일을다시사용하기가어려움 다중소스파일 서로관련된코드만을모아서하나의소스파일로할수있음 소스파일을재사용하기가간편함 소스파일 23
multiple_source.c // 다중소스파일 #include <stdio.h> #include "power.h" 예제 #1 power.h // power.c에대한헤더파일 #ifndef POWER_H #define POWER_H double power(int x, int y); 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)); return 0; #endif power.c // 다중소스파일 #include "power.h" double power(int x, int y) { double result = 1.0; int i; for(i = 0;i < y; i++) result *= x; } return result; 24
비트단위연산자 C에서는비트단위의연산도가능하다. 비트단위연산자는정수에만적용이가능하다. 연산자 연산자의의미 설명 & 비트 AND 두개의피연산자의해당비트가모두 1이면 1, 아니면 0 비트 OR 두개의피연산자의해당비트중하나만 1이면 1, 아니면 0 ^ 비트 XOR 두개의피연산자의해당비트의값이같으면 0, 아니면 1 << 왼쪽으로이동 지정된개수만큼모든비트를왼쪽으로이동한다. >> 오른쪽으로이동 지정된개수만큼모든비트를오른쪽으로이동한다. ~ 비트 NOT 0은 1로만들고 1은 0로만든다. 25
비트논리곱연산자 비트1 비트2 비트1 & 비트2 0 0 0 0 1 0 1 0 0 1 1 1 변수 1 00000000 00000000 00000000 00001101 (13) 변수 2 00000000 00000000 00000000 00001110 (15) ------------------------------------------------------- ( 변수 1 AND 변수 2) 00000000 00000000 00000000 00001100 (12) 마스크연산으로많이사용 변수 1 00000000 00000000 00000000 00001101 (13) 마스크 00000000 00000000 00000000 00000111 (7) ------------------------------------------------------- ( 마스크연산후 ) 00000000 00000000 00000000 00000101 (5) 26
bit_and.c 1. // 비트단위 AND 2. #include <stdio.h> 3. int main(void) 4. { 5. int x = 13; // 00000000 00000000 00000000 00001101 6. int y = 15; // 00000000 00000000 00000000 00001110 7. int z = x & y; // 00000000 00000000 00000000 00001100 8. printf("%08x \n", z); 9. return 0; 10. } 0000000D 27
비트논리합연산자 비트1 비트2 비트1 비트2 0 0 0 0 1 1 1 0 1 1 1 1 변수 1 00000000 00000000 00000000 00001001 (9) 변수 2 00000000 00000000 00000000 00001010 (10) ------------------------------------------------------- ( 변수 1 OR 변수 2) 00000000 00000000 00000000 00001011 (11) 비트설정연산으로많이사용 변수 1 00000000 00000000 00000000 00001001 (9) 비트설정 00000000 00000000 00000000 00000111 (7) ------------------------------------------------------- ( 비트 OR 연산후 ) 00000000 00000000 00000000 00001111 (15) 28
bit_or.c 1. // 비트단위 OR 2. #include <stdio.h> 3. int main(void) 4. { 5. int x = 9; // 00000000 00000000 00000000 00001001 6. int y = 10; // 00000000 00000000 00000000 00001010 7. int z = x y; // 00000000 00000000 00000000 00001011 8. printf("%08x \n", z); 9. return 0; 10. } 0000000B 29
비트배타논리합연산자 비트1 비트2 비트1 ^ 비트2 0 0 0 0 1 1 1 0 1 1 1 1 변수 1 00000000 00000000 00000000 00001001 (9) 변수 2 00000000 00000000 00000000 00001010 (10) ------------------------------------------------------- ( 변수 1 XOR 변수 2) 00000000 00000000 00000000 00000011 (3) 30
비트부정연산자 비트 1 ~ 비트 1 0 1 1 0 부호비트가반전되었기때문에음수가된다. 변수 1 00000000 00000000 00000000 00001001 (9) ------------------------------------------------------- (NOT 변수 1) 11111111 11111111 11111111 11110110 (-10) 31
bit_not.c 1. // 비트단위 NOT 2. #include <stdio.h> 3. int main(void) 4. { 5. int x = 9; // 00000000 00000000 00000000 00001001 6. int z = ~x; // 11111111 11111111 11111111 11110110 7. printf("%08x (%d)\n", z, z); 8. return 0; 9. } FFFFFFF6 (-10) 32
비트이동연산자 연산자기호설명 왼쪽비트이동 << x << y x 의비트들을 y 칸만큼왼쪽으로이동 오른쪽비트이동 >> x >> y x 의비트들을 y 칸만큼오른쪽으로이동 00000000 00000000 00000000 00001111 처음상태 (15) 00000000 00000000 00000000 00001111 왼쪽으로비트이동 삭제 00000000 00000000 00000000 00001111 삽입 경계를벗어나는비트를삭제하고오른쪽빈곳은채운다. 00 00000000 00000000 00000000 00111100 최종상태 (60) 왼쪽비트이동연산 33
오른쪽비트이동연산 ( 양수 ) 부호비트는 0 00000000 00000000 00000000 00001111 처음상태 (15) 부호비트가 0 이므로 0 을삽입한다. 00 00000000 00000000 00000000 00001111 00000000 00000000 00000000 00001111 00000000 00000000 00000000 00000011 삭제 오른쪽으로비트이동 경계를벗어나는비트를삭제한다. 최종상태 (3) 오른쪽비트이동연산 ( 양수 ) 34
오른쪽비트이동연산 ( 음수 ) 부호비트는 1 11111111 11111111 11111111 11110011 처음상태 (-11) 부호비트가 1 이므로 1 을삽입한다. 11 11111111 11111111 11111111 11110011 11111111 11111111 11111111 11110011 삭제 오른쪽으로비트이동 경계를벗어나는비트를삭제한다. 11111111 11111111 11111111 11111100 최종상태 (-2) 오른쪽비트이동연산 ( 음수 ) 35
비트필드구조체 멤버가비트단위로나누어져있는구조체 struct 태그이름 { 자료형멤버이름 1: 비트수 ; 자료형멤버이름 2: 비트수 ; }; struct product { unsigned style : 3; unsigned size : 2; unsigned color : 1; }; unsigned int 1 2 3 color size style 36
bit_field.c 1. // 비트필드구조체 2. #include <stdio.h> 3. 4. struct product { 5. unsigned style : 3; 6. unsigned size : 2; 7. unsigned color : 1; 8. }; 9. 10. int main(void) 11. { 12. struct product p1; 13. 14. p1.style = 5; 15. p1.size = 3; 16. p1.color = 1; 17. 18. printf("style=%d size=%d color=%d\n", p1.style, p1.size, p1.color); 19. printf("sizeof(p1)=%d\n", sizeof(p1)); 20. printf("p1=%x\n", p1); 21. 22. return 0; 23. } style=5 size=3 color=1 sizeof(p1)=4 p1=ccccccfd 37
비트필드사용시에주의점 struct product { long code; // 1 일반멤버도가능하다. unsigned style : 3; unsigned : 5; // 2 자리만차지한다. unsigned size : 2; unsigned color : 1; unsigned : 0; // 3 현재워드의남아있는비트를버린다. unsigned state : 3; // 여기서부터는다음워드에서할당된다. }; 비트필드의응용분야 : 하드웨어포트제어 38
Q & A 39