Chapter 05 전처리와 입출력
헤더파일 텍스트 파일 헤더파일(header file)은 확장자가 *.h로 전처리기 지시자인 #include, #define 등과 자료형의 재정의, 함수의 원형(prototype)을 포함하는 텍스트 파일 헤더파일은 소스와 같은 텍스트 파일이므로 필요하면 그 내용 보기 가능 다음은 함수 main() 위에 항상 끼워 넣은 헤더 파일 stdio.h의 일부 위 헤더파일은 시스템 헤더파일로 개발도구에서 제공하는 헤더파일 … typedef unsigned int size_t; #define EOF (-1) _CRTIMP int __cdecl printf(const char *, ...); #define getchar() getc(stdin) #define putchar(_c) putc((_c),stdout)
시스템, 사용자 헤더파일 사용자 헤더 파일 시스템 헤더 파일 시스템 헤더파일과 같이, 필요하면 프로그래머도 직접 헤더파일 생성 가능 사용자가 직접 작성한 헤더파일은 지시자 #include를 이용하는 경우 다음과 같이 큰 따옴표를 이용 헤더파일의 큰 따옴표는 헤더파일이 기술된 폴더와 시스템 인클루드 폴더를 차례로 검색 시스템 헤더 파일은 대부분 개발도구가 설치된 폴더에서 하부 [include]라는 이름의 폴더에 존재 시스템 헤더 파일 필요한 처리에 따라 다음 해당하는 헤더 파일을 포함 #include <stdio.h> #include “myheader.h” 헤더파일 처리 작업 stdio.h 표준 입출력 작업 math.h 수학 관련 작업 string.h 문자열 작업 time.h 시간 작업 ctype.h 문자 관련 작업
사용자 헤더파일 header.c와 myheader.h로 나누어 처리 헤더 파일 myheader.h는 소스 header.c와 동일한 폴더에 저장 소스파일 header.c 와 헤더파일 myheader.c /* 파일 : header.c */ #include <stdio.h> //printf()의 이용을 위한 헤더 파일 포함 /*>>>>>>>>>>>>>> main() 함수 시작 <<<<<<<<<<<<<<<<*/ int main(void) { printf("사용자가 만드는 헤더 파일의 이용 방법을 알아 봅시다.\n"); return 0; } /*>>>>>>>>>>>>>> main() 함수 종료 <<<<<<<<<<<<<<<<*/
개발도구 Visual C++에서의 헤더 파일 다음 그림과 같이 왼쪽 창의 Header Files 폴더 하부에 헤더 파일 myheader.h를 만들도록
기호상수 정의 #define 전처리기 지시자인 #define은 소스에서 지정된 기호상수 (symbolic constant)를 정의된 치환문자열로 대체(치환) 일반적으로 프로그램의 이해를 쉽게 하기 위하여 기호상수는 대문자로 기술 #define 지시자 하부의 소스에서 PHI라는 식별자는 항상 3.141592라는 값으로 대체
기호상수의 필요성 장점 지시자 #define은 시스템에 따라 변할 수 있는 상수를 한번에 수정할 수 있고, 수정되는 한 부분만 검사하면 되므로 이식성과 신뢰성이 증대 이식성은 portability 라고 하며 한번 구현한 프로그램은 여러 시스템에서 쉽게 실행 가능함을 말함
예제 소스 Define.c 문자상수 PHI를 3.14로 정의하여 반지름이 2인 원의 둘레를 구하는 프로그램
지시자는 한 줄에 줄의 마지막 \ 지시자 #define에서 치환문자열이 길어 한 줄에 코딩이 불편한 경우, 계속되는 줄 끝에 역슬래쉬 \를 넣어 줄이 계속되고 있음을 표시해야 함 모든 지시자는 원칙적으로 한 줄에 하나의 지시자를 코딩 해야 하므로 여러 줄의 지시자를 입력하기 위해서는 줄 끝에 역슬래쉬 \를 이용 #define MSG “프로그램 언어의 학습은 일반 언어의 학습과 마찬가지로 반복학습이 중요하다” #define MSG “프로그램 언어의 학습은 일반 \ 언어의 학습과 마찬가지로 반복학습이 중요하다”
인자의 필요성 인자가 없는 기호상수 지시자 #define의 바로 뒤에 나오는 문자열을 기호상수 또는 매크로 다음과 같이 수의 제곱승을 구하는 매크로를 만든다고 하자. 그러나 아래 소스는 원하는 정수에 대하여 매크로를 모두 만들어야 하는 문제 #define SQUARE2 2 * 2 #define SQUARE3 3 * 3 … printf(“%d, %d”, SQUARE2, SQUARE3); 2 * 2 로 치환 3 * 3 로 치환
인자의 이용 인자 위의 문제를 해결하는 방안이 인자(parameter)를 이용하는 방법 기호 상수에서 이름 뒤에 괄호 ( ) 사이에 인자를 이용 인자는 프로그래머가 지정하는 식별자를 이용하고, 이 인자를 치환문자열에 사용 여러 인자가 필요한 경우는 SUM(x,y)과 같이 콤마로 인자를 구분
주의사항 괄호의 이용 매크로를 정의하는 경우, 괄호의 이용은 매우 중요 다음에서 괄호를 생략하면 심각한 문제가 발생 다음 소스에서 변수 a에는 3의 제곱승인 9가 저장되지 못하고, 5가 저장 이러한 문제를 방지하기 위해서는 모든 인자와 외부에 괄호를 잘 이용 기호 상수에서 매크로 이름과 괄호 ( 사이에는 공백이 올 수 없다. 아래와 같이 공백이 들어가는 경우 매크로 SQUARE를 문자열 (x) ((x) * (x))로 치환하는 의미 #define SQUARE(x) (x * x) … a = SQUARE(1+2); 인자 x는 1+2 자체가 되므로 (1+2 * 1+2)로 치환되어 우선 순위에 따라 결과 값이 5가 된다. #define SQUARE (x) ((x) * (x))
예제 소스 Square.c 이 프로그램은 인자의 수를 제곱한 결과를 구하는 매크로 SQUARE(x)를 구현한 프로그램
예제 소스 Macro.c 원의 둘레를 구하는 매크로의 정의하여 이용하는 프로그램
자료형의 재정의 typedef typedef는 전처리기가 처리하는 지시자가 아니라 C 언어의 문장 typedef 앞에는 #이 없으며 문장 마지막에는 세미콜론(;)이 나와야 하고, 지시자인 #define과는 다르게 자료형의 재정의에만 이용이 가능 키워드 typedef를 이용하여 이미 정해진 자료 유형을 다른 이름으로 재정의 재정의 문장은 주로 다른 전처리기 지시자와 같이 일반적으로 헤더 파일에 기술, 물론 소스에 기술해도 무관 아래 구문을 이용하면 myint는 int와 같은 자료형이 되고, myint는 다른 형과 마찬가지로 선언문에서 사용 가능 자료형 unsigned long 을 짧은 이름 u_long 으로 재정의 구문 typedef unsinged long u_long;
자료 재정의 필요성 호환성 문제 해결 int salary = 2000000; 터보 C++에서 자료 유형 int는 저장공간의 크기가 2바이트이나 비쥬얼 C++는 4바이트 그러므로 비쥬얼 C++에서 작성한 다음과 같은 프로그램은 터보 C++에서는 문제가 발생 이유는 2바이트로는 2000000을 저장할 수 없기 때문 문제 해결 비쥬얼 C++에서는 다음과 같이 int를 myint로 재정의하여 모든 int의 형을 모두 myint로 코딩 이 코드를 터보 C++에서 이용해야 할 경우에는 typedef 문장을 수정하면 나머지 소스는 수정할 필요 없이 그대로 이용 가능 int salary = 2000000;
예제 소스 Typedef.c 자료형 int 형을 새로운 자료형 integer로 정의하여, 변수 a를 선언하고 초기값으로 10을 저장하여 출력
표준입력 함수 scanf() scanf(“%d”, &age); 함수 scanf()의 사용법은 printf()와 유사 자료형 int 변수 age에 입력 값을 저장하려면 일반 변수 앞에는 변수의 주소를 의미하는 문자 &를 반드시 추가 &은 주소를 의미하는 연산자 scanf(“%d”, &age);
예제 소스 Scanf.c 함수 scanf()를 이용하여 숫자 18을 키보드로 입력하여 변수 age에 저장한 후, 이 값을 이용하여 다음과 같은 출력이 나오도록 프로그램
변환 명세 함수 scanf()에서 scanf(“%d %f”, &age, &weight); 임의의 갯수의 입력을 받을 수 있고, 이런 경우 적절히 변환 명세를 이용하여 입력 값을 지정 scanf(“%d %f”, &age, &weight); 변환 명세 의미 %d, %i 정수 자료형에 정수 저장 %u 자료형 unsigned int형에 정수 저장 %o 정수 자료형에 8진수 형태 입력 값 저장 %x, %X 정수 자료형에 16진수 형태 입력 값 저장 %f 실수 float 자료형에 소수 형태 입력 값 저장 %lf 실수 double 자료형에 소수 형태 입력 값 저장 %e, %E 지수형 형태의 실수 자료값을 저장 %c 문자 자료형에 문자 저장 %s 여러 개 일련의 문자인 문자열(string) 저장 %p 주소 값으로 16진수의 unsigned int 형을 저장
예제 소스 Scanftype.c 키보드로부터 키, 8진수, 16진수, 몸무게, 혈액형을 입력 받아 저장, 출력하는 프로그램 각각의 입력 값을 저장할 자료형을 고려하여 변수를 선언한 후 함수 scanf()를 이용하여 입력 값을 저장 문자 입력 위 소스 22라인을 주의 함수 scanf()를 호출하는 인자가 “\n%c” 다른 함수 scanf() 호출에서는 \n을 이용하지 않으나 22줄에서만 \n을 이용 만일 여러분이 무심코 22라인을 scanf(“%c”)로 코딩하였다면 프로그램 실행에서 원하는 결과가 나오지 않음 몸무게를 입력한 후 Enter 키를 누른 값이 \n으로 입력되고, 이 후 입력하는 문자가 변수 blood에 저장되게 하기 위함
출력 함수 함수 printf() 모든 종류의 자료형을 출력하는 함수 제어문자열과 표현식을 이용하여 출력하는데, 제어문자열(control string)에는 출력하려는 표현식 값에 따라 변환명세 (conversion specification)를 차례로 기술 변환명세는 변환문자열이라고도 표현 제어문자열 내부의 변환명세는 표현식의 수와 값의 종류에 따라 서로 순서대로 일치 printf (“ … %d … %f …“, 정수표현식, 실수표현식); 이 부분이 출력 내용의 전체적인 문자열의 구조와 변환명세를 기술하는 제어문자열이다.
변환 문자 변환 명세 의미 기본 폭 %d, %i 정수 자료형 정수 출력 값의 폭 %u 부호 없는 정수 자료형 정수 출력 %o 정수 자료형 8진수 형태 출력 출력되는 8진수 앞에 0이 나타남. %x, %X %#x, %#X 정수 자료형 16진수 형태 출력 출력되는 16진수 앞에 0x(0X)가 나타남. %f 부동소수형 float 소수 형태 출력 소수점 이하 6자리 %lf 부동소수형 double 소수 형태 출력 %e, %E 부동소수형 지수 형태 출력 %g, %G e(E) 형식과 f 형식 중에서 짧은 형태 출력 %c 문자 출력 %s 문자열 출력 %p 주소 값을 16진수 형태로 출력 %% %의 출력
정수 필드 폭과 정렬 출력하려는 정수 값의 필드 폭(width)을 지정하려면 %d 사이에 폭을 나타내는 정수를 기술 마찬가지로 출력 값의 정렬은 필드 폭 앞에 빼기기호 - 를 넣어서 좌측정렬로 지정
실수 필드 폭과 정렬 부동소수형을 출력하는 경우 가변 폭 지정 변환명세에서 필드 폭(width)을 지정하려면 %f 사이에 폭을 기술 만일 변환명세가 %10.5f 이면 전체 폭은 10, 그 중에서 5는 소수점 이하 자리수의 폭을 의미 %10f 라고 기술하면 전체 폭은 10이고 소수점 이하 자리수의 폭은 기본(default)인 6으로 지정 지정한 전체 폭이 출력 값의 전체 폭보다 작으면, 지정된 작은 폭은 무시하고 원래의 출력 값의 폭으로 출력 가변 폭 지정 *를 이용 전체 폭이 m, 소수 이하는 n printf(“%*.*f”, m, n, 3.1);
출력에서의 탈출 기법 탈출 기법(escape sequences) 탈출 기법을 이용한 문자를 함수 printf()에서 제어문자열이나 표현식에서 이용이 가능 탈출 문자를 이용한 다음 구문의 출력은? 제어문자열 "\"%s\"\n" 을 구성하는 각각의 의미는? 제어문자열 요소 의미 \” 글자 ‘대’ 앞에 “ 를 출력하기 위한 문자 %s 문자열 대한민국 을 출력하기 위한 변환명세 글자 ‘국’ 뒤에 “ 를 출력하기 위한 문자 \n 새 줄로 다음 출력을 위한 이동
예제 소스 Printescape.c 함수 printf()의 제어문자열을 살펴보고 이해
예제 소스 Fieldwidth.c 다음과 같은 출력이 나오도록 함수 printf()의 제어문자열과 변환명세를 고려하여 프로그램을 작성
문자 입출력 char c; c = getchar(); putchar(c); 문자 하나 이 함수를 이용하려면 헤더 파일 stdio.h 파일을 첨가 함수 getchar()를 이용하여 문자를 하나 입력 받으려면 인자가 없는 getchar()를 이용 입력 받은 문자를 저장하려면 자료형 char나 정수형으로 선언된 변수를 이용하여 저장 문자의 출력은 함수 putchar()의 인자에 출력하려는 문자를 기술하여 출력 char c; c = getchar(); putchar(c);
예제 소스 Getchar.c 하나의 문자를 입력 받아 출력하는 프로그램을 함수 getchar()와 putchar()를 이용하여 작성
프로그램 연습 프로그램 목적 파일 구성 다음 조건을 만족하는 헤더 파일과 매크로를 작성 다음과 같이 자료형 double인 원의 반지름을 입력 받아, 원의 둘레와 원의 면적을 구하는 프로그램을 작성 파일 구성 프로그램 저장 장소 : D:\source 폴더 프로젝트 이름 : circle 소스 파일 이름 : circle.c 헤더 파일 : circle.h 다음 조건을 만족하는 헤더 파일과 매크로를 작성 헤더파일 circle.h에는 매크로와 출력을 위한 시스템 헤더 파일을 첨가하는 소스 구성 원주율 3.14를 PHI 정의 매크로 CIRCUM(x)은 인자 x가 반지름인 원에서 원의 둘레를 구하는 매크로를 정의 매크로 AREA(x)는 인자 x가 반지름인 원에서 원의 면적을 구하는 매크로를 정의 소스 파일 circle.c에서는 double 형의 반지름을 표준 입력으로 받아 위의 결과를 출력 반지름은 표준입력으로 저장 반지름과 원의 둘레(매크로 CIRCUM(x) 이용)를 출력 반지름과 원의 면적(매크로 AREA(x) 이용)을 출력
파일 소스파일 헤더파일 결과