C프로그래밍 2강 - 자료형과 선행처리기
C 언어의 기본 자료형과 열거형, 여러 형태의 상수를 학습하고 변수를 선언할 때 고려할 범위·위치·초기화 문제를 살펴본다. 이어서 헤더 파일 포함, 매크로 정의와 해제, 조건부 컴파일 등 대표적인 선행처리 기능을 정리한다.
1. 자료형의 개념과 종류
자료형이 정의하는 것
자료형(data type)은 컴퓨터에서 값을 표현하는 방법을 정의한 것이다. 값의 종류에 따라 서로 다른 2진수 표현 방법을 사용하며, 값을 저장하기 위해 필요한 메모리 공간의 크기와 그 값을 대상으로 수행할 수 있는 연산도 자료형에 의해 결정된다.
C 언어는 값을 저장하거나 계산할 때 자료형을 엄격하게 구분한다. 서로 다른 자료형을 함께 처리해야 할 때에는 필요한 경우 자료형을 변환하여 올바른 결과가 나오도록 해야 한다.
C 언어 자료형의 분류
| 분류 | 종류 | 주요 자료형 |
|---|---|---|
| 기본형 | 정수형 | short int, int, long int, long long int, signed 또는 unsigned |
| 문자형 | char, signed 또는 unsigned | |
| 실수형 | float, double, long double | |
| 열거형 | 나열한 단어를 정수 값으로 사용하는 자료형 | |
| 파생형 | 배열형, 구조체형, 공용체형, 포인터형 | |
시험 포인트: 자료형은 단순히 값의 이름만 구분하는 것이 아니라 표현 방법, 메모리 크기, 가능한 연산을 함께 규정한다.
2. 문자형과 정수형
크기와 값의 범위
문자형과 정수형은 모두 정수 형태의 값을 표현한다. 부호가 있는 signed형과 부호가 없는 unsigned형으로 나타낼 수 있으며, 별도로 지정하지 않으면 signed가 기본이다. unsigned형은 음수를 표현하지 않는 대신 같은 크기의 signed형보다 큰 양의 정수까지 표현할 수 있다.
정수형의 크기는 구현 환경에 따라 달라질 수 있지만 다음의 크기 관계는 유지된다.
sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)
int는 해당 컴퓨터에서 가장 효율적으로 처리할 수 있는 정수형으로 구현된다. 강의에서 제시한 32비트 또는 64비트 컴퓨터의 대표적인 크기와 범위는 다음과 같다.
| 자료형 | 크기 | signed 범위 | unsigned 범위 |
|---|---|---|---|
| char | 1바이트 | -128~127 | 0~255 |
| short int | 2바이트 | -32,768~32,767 | 0~65,535 |
| int | 4바이트 | -2,147,483,648~2,147,483,647 | 0~4,294,967,295 |
| long int | 4바이트 | -2,147,483,648~2,147,483,647 | 0~4,294,967,295 |
| long long int | 8바이트 | -9,223,372,036,854,775,808~9,223,372,036,854,775,807 | 0~18,446,744,073,709,551,615 |
limits.h와 문자 자료
실제 구현 환경에서 정수형이 표현할 수 있는 범위는 limits.h에 정의된 값을 이용해 확인할 수 있다. 예를 들어 INT_MIN과 INT_MAX는 각각 int형의 최솟값과 최댓값을 나타낸다.
char형에는 문자의 내부 표현인 정수 코드를 저장한다. 예를 들어 'A'의 ASCII 코드는 65이며, 16진수 0x42를 char 변수에 저장하면 문자 'B'로 해석할 수 있다.
3. 실수형과 열거형
실수형
실수형은 IEEE 754에 따른 부동소수점 표현 방식으로 값을 표현한다. 강의의 실행 환경에서 float는 4바이트, double과 long double은 8바이트로 제시되었다. float의 양의 값 범위는 약 1.175494351×10-38~3.402823466×1038, double은 약 2.2250738585072014×10-308~1.7976931348623158×10308이다.
실제 환경에서 실수형의 범위는 float.h의 기호 상수로 확인한다. DBL_MIN과 DBL_MAX는 double형의 양의 최솟값과 최댓값을 나타낸다.
열거형
열거형(enumeration type)은 나열한 단어를 값으로 사용하는 자료형이다. 별도의 값을 지정하지 않으면 첫 번째 이름은 0이고 이후 이름에는 1씩 증가한 정수가 대응한다.
enum day { SUN, MON, TUE, WED, THU, FRI, SAT };
/* SUN=0, MON=1, TUE=2, ..., SAT=6 */
특정 이름에 직접 값을 지정할 수도 있다. enum fruit { APPLE, PEAR, MANGO=4, GRAPE };에서는 APPLE=0, PEAR=1, MANGO=4가 되고, 지정된 값 다음의 GRAPE는 5가 된다.
열거형에서 중간 항목의 값을 지정하면 그다음 항목은 지정된 값에서 1 증가한 값을 갖는다.
4. 정수형과 실수형 상수
상수의 의미
상수(constant)는 항상 고정된 값을 갖는 자료이다. C에서는 상수의 자료형에 따라 정해진 문법으로 값을 표기한다. 예를 들어 'a', 123, 1.2e-3, "KNOU"는 각각 문자, 정수, 실수, 문자열 상수이다.
정수형 상수의 진법과 접미사
| 구분 | 예 | 표현 규칙 |
|---|---|---|
| 10진 상수 | 10, -45, 999 | 0~9를 사용하며 첫 자리는 0이 아님 |
| 8진 상수 | 012, -055 | 0~7을 사용하며 0으로 시작 |
| 16진 상수 | 0x0c, -0X2D | 0~9와 a~f를 사용하며 0x 또는 0X로 시작 |
| unsigned형 | 10u, 012u, 0X0CU | 접미사 u 또는 U 사용 |
| long형 | 12345l, 0XFFL | 접미사 l 또는 L 사용 |
실수형 상수
실수형 상수는 소수점 형식인 3.14, -12.345 또는 지수 형식인 1.2e3, 5e-2로 표현한다. 접미사가 없으면 double형이 기본이다. float형은 3.14f처럼 f 또는 F를, long double형은 3.14L처럼 l 또는 L을 붙인다.
정수 상수의 앞부분은 진법을, 실수 상수의 뒷부분은 자료형을 구별한다. 012는 8진수이고, 3.14f는 float형 상수이다.
5. 문자형 상수와 문자열 상수
문자형 상수
문자형 상수는 작은따옴표로 묶은 한 개의 문자이다. 영문자, 숫자, 기호뿐 아니라 공백·탭·줄 바꿈 같은 백색문자와 널 문자도 표현할 수 있다. 문자형 상수의 내부에는 해당 문자의 ASCII 코드값이 저장된다.
키보드에 직접 나타나지 않거나 기본 방식으로 표현하기 어려운 문자는 백슬래시를 사용하는 이스케이프 문자로 나타낸다.
| 이스케이프 문자 | 기능 |
|---|---|
\a | 경고음 |
\b | 백스페이스 |
\f | 새 페이지 |
\n | 줄 바꿈 |
\r | 행의 시작 위치로 이동 |
\t | 수평 탭 |
\0 | ASCII 코드 0인 널 문자 |
\', \", \\ | 작은따옴표, 큰따옴표, 백슬래시 |
ASCII 코드로 문자를 나타낼 수도 있다. 문자 A는 8진 코드로 '\101', 16진 코드로 '\x41'과 같이 표현한다.
문자열 상수
문자열 상수는 큰따옴표로 묶은 일련의 문자이다. 컴퓨터 메모리에는 각 문자가 순서대로 저장되고 문자열의 끝을 표시하기 위한 널 문자 '\0'가 자동으로 추가된다. 따라서 "SEOUL KOREA"의 실제 저장 내용 끝에도 널 문자가 포함된다.
문자 상수는 작은따옴표로 묶은 한 문자이고, 문자열 상수는 큰따옴표로 묶은 문자들의 나열이며 끝에 널 문자가 추가된다.
6. 변수의 선언과 기본 성질
변수란 무엇인가
변수(variable)는 프로그램에서 값을 저장하기 위한 기억공간이다. 상수와 달리 프로그램 실행 도중 저장된 값을 변경할 수 있다. C에서는 모든 변수를 사용하기 전에 선언해야 한다.
모든 변수는 이름, 정해진 자료형, 할당된 값을 갖는다. 선언의 기본 형식은 자료형 변수명;이며 같은 자료형의 여러 변수를 자료형 변수명1, 변수명2;와 같이 한 문장에서 선언할 수도 있다.
int a;
double b;
a = 3 + 2;
b = a / 4.0;
이 예에서 정수형 변수 a에는 5가 저장되고, 실수형 변수 b에는 1.25가 저장된다. 변수를 선언할 때에는 저장할 값의 크기, 선언 위치, 초기화 여부를 함께 고려해야 한다.
7. 변수 선언 시 고려할 사항
오버플로와 언더플로
변수의 자료형이 표현할 수 있는 값의 범위를 벗어나면 오버플로(overflow) 또는 언더플로(underflow) 문제가 생긴다. 강의의 2바이트 short int 예에서 최댓값 32,767에 1을 더하면 -32,768이 되고, 최솟값 -32,768에서 1을 빼면 32,767이 되는 결과가 나타난다.
같은 계산 결과를 표현 범위가 더 넓은 int형 변수에 저장하면 32,768과 -32,769를 정상적으로 담을 수 있다. 따라서 계산 중 만들어질 값까지 고려하여 충분한 범위의 자료형을 선택해야 한다.
변수의 선언 위치
함수 바깥에 선언한 변수는 전역변수이고, 함수나 블록 안에서 선언한 변수는 지역변수이다. 서로 다른 함수에 같은 이름의 지역변수를 선언해도 각각 별개의 변수로 취급된다. 전역변수와 지역변수의 이름이 같으면 해당 함수 안에서는 지역변수가 사용된다.
예를 들어 전역변수 a가 100이고 func() 안의 지역변수 a가 200이라면, main 함수에서는 전역변수의 값 100을 출력하고 func 함수에서는 지역변수의 값 200을 출력한다.
변수의 초기화
변수의 값을 사용하기 전에는 적절한 값이 저장되어 있어야 한다. 초기화하지 않은 지역변수를 연산에 사용하면 예상할 수 없는 값이 결과에 섞일 수 있다. 1부터 10까지 합을 구할 때 누적 변수 sum을 0으로 초기화해야 올바른 결과 55를 얻는다.
변수를 선언했다는 사실만으로 사용할 준비가 끝난 것은 아니다. 자료형의 범위와 변수의 유효 영역을 확인하고, 값을 읽기 전에 반드시 올바른 초기값이 들어 있는지 점검해야 한다.
8. 선행처리와 헤더 파일 포함
선행처리의 개념과 지시어
선행처리(preprocessing)는 컴파일에 앞서 소스 프로그램을 가공하여 컴파일러가 실제로 번역할 소스 프로그램을 만드는 과정이다. 선행처리 지시어는 #으로 시작하고, 한 행에 하나의 지시어를 작성하며, 문장 끝에 세미콜론을 사용하지 않는다.
| 기능 | 대표 지시어 |
|---|---|
| 헤더 파일 포함 | #include |
| 매크로 선언과 해제 | #define, #undef |
| 조건부 컴파일 | #if, #elif, #else, #endif |
#include 지시어
#include는 지정한 헤더 파일의 내용을 해당 위치에 포함한다. #include <파일명>은 표준 디렉터리에서 파일을 찾으므로 stdio.h, stdlib.h, math.h 같은 표준 헤더에 사용한다.
#include "파일명"은 현재 사용 중인 디렉터리 또는 직접 지정한 경로에서 파일을 찾는다. 따라서 사용자가 작성한 a.h는 #include "a.h", 하위 폴더의 b.h는 #include "sub/b.h"처럼 포함할 수 있다.
9. 매크로 정의와 해제
매크로 상수
매크로(macro)는 특정 코드 패턴으로 치환되도록 정의한 명칭이다. #define을 사용하면 자주 쓰는 명령, 수식, 상수에 대표 이름을 붙일 수 있다. 매크로 상수는 #define 매크로명 값 형식으로 정의하고 #undef 매크로명으로 해제한다.
#define PI 3.141592
/* 이후의 PI는 3.141592로 치환됨 */
#undef PI
매크로 함수와 괄호
매크로 함수는 #define 매크로명(인수리스트) (수식) 형식으로 정의한다. 함수 호출처럼 보이지만 실제로는 인수를 수식에 반영한 텍스트 치환이다. 그러므로 인수와 전체 수식을 적절한 괄호로 묶어야 한다.
#define C_AREA(x) (3.141592 * (x) * (x))
C_AREA(r + 5)는 (3.141592 * (r + 5) * (r + 5))로 올바르게 확장된다. 반면 #define C_AREA(x) (3.141592 * x * x)처럼 인수에 괄호가 없으면 r + 5를 전달했을 때 (3.141592 * r + 5 * r + 5)로 치환되어 의도와 다른 결과가 나온다.
매크로 함수는 계산을 실행하는 실제 함수가 아니라 소스 코드의 텍스트 치환이다. 연산 우선순위 문제를 막기 위해 인수와 수식 전체에 괄호를 사용하는 습관이 중요하다.
10. 조건부 컴파일
조건에 따라 컴파일할 코드 선택하기
조건부 컴파일은 조건에 따라 컴파일될 소스 코드를 선택하는 기능이다. #if 조건문과 #endif 사이의 코드는 조건이 참일 때만 컴파일할 소스에 포함된다. #else를 사용하면 참과 거짓일 때 포함할 코드를 나눌 수 있고, 여러 조건은 #elif로 연결한다.
#if 조건문1
문장1
#elif 조건문2
문장2
#else
문장3
#endif
조건은 컴파일 이전의 선행처리 과정에서 참과 거짓을 판단할 수 있어야 하므로 변수 지정이나 함수 호출을 사용할 수 없다. 강의의 예에서 #define DEBUG_MODE 1이면 평균을 계산할 두 값과 평균이 모두 출력되고, DEBUG_MODE 0이면 디버깅용 출력은 제외되고 평균만 출력된다.
조건부 컴파일은 실행 중 조건을 검사하는 일반적인 if문과 다르다. 어떤 코드가 컴파일 대상에 포함될지를 컴파일 전에 결정한다.
핵심 개념 정리
- 자료형은 값의 2진수 표현 방법, 메모리 크기, 가능한 연산을 정의한다.
- C의 자료형에는 정수·문자·실수 기본형, 열거형, 배열·구조체·공용체·포인터 등의 파생형이 있다.
- 문자형과 정수형은 정수 값을 표현하며 signed가 기본이고 unsigned는 0 이상의 값만 표현한다.
- 열거형은 이름을 순서대로 0부터 시작하는 정수 값에 대응시키며 특정 값을 직접 지정할 수 있다.
- 정수 상수는 10진·8진·16진 표기와 접미사를, 실수 상수는 소수·지수 표기와 자료형 접미사를 사용한다.
- 문자 상수는 작은따옴표, 문자열 상수는 큰따옴표로 묶으며 문자열 끝에는 널 문자가 추가된다.
- 변수는 사용 전에 선언해야 하며 값의 범위, 선언 위치, 초기화를 고려해야 한다.
- 선행처리는 컴파일 전 소스를 가공하며 헤더 포함, 매크로, 조건부 컴파일이 대표적이다.
- 매크로 함수는 텍스트 치환이므로 인수와 전체 수식을 괄호로 묶어야 한다.
최종 정리: 자료형은 값의 표현 가능 범위와 연산의 기반이고, 변수는 그 자료형에 맞는 값을 담는 기억공간이다. 선행처리기는 컴파일보다 먼저 헤더와 매크로, 조건에 따른 코드 선택을 반영하므로 일반 실행 문장과 처리 시점을 구별해야 한다.
예상문제 20선
1. 자료형이 정의하는 내용으로 옳지 않은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
자료형은 값의 표현, 메모리 크기와 연산을 정의하지만 파일의 저장 위치와는 관계가 없다.
2. 다음 중 파생형 자료형에 해당하는 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
배열형, 구조체형, 공용체형, 포인터형은 C의 파생형 자료형이다.
3. 문자형과 정수형의 부호를 별도로 지정하지 않았을 때 기본은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
문자형과 정수형은 signed형 또는 unsigned형으로 표현하며 signed가 기본이다.
4. int형의 실제 최솟값과 최댓값을 확인할 때 사용하는 헤더 파일은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④limits.h의 INT_MIN과 INT_MAX 등으로 정수형의 범위를 확인할 수 있다.
5. 부동소수점 방식으로 값을 표현하는 자료형은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
float, double, long double 등의 실수형은 부동소수점 표현 방식을 사용한다.
6. enum fruit { APPLE, PEAR, MANGO=4, GRAPE };에서 GRAPE의 값은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
MANGO에 4를 지정했으므로 다음 항목인 GRAPE에는 1 증가한 5가 대응한다.
7. 다음 중 8진 정수형 상수는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
8진 상수는 0으로 시작하며 0~7 범위의 숫자를 사용한다.
8. float형 실수 상수를 나타내는 접미사는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
실수 상수는 기본적으로 double형이며 f 또는 F를 붙이면 float형이 된다.
9. 줄 바꿈을 나타내는 이스케이프 문자는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①\n은 new line, 즉 줄 바꿈을 나타낸다.
10. 문자열 상수에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
문자열은 큰따옴표로 묶은 일련의 문자이며 끝을 표시하는 널 문자가 자동으로 붙는다.
11. 변수의 특징으로 옳지 않은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
변수는 프로그램 실행 도중 값을 변경할 수 있는 기억공간이다.
12. 변수 선언 시 반드시 고려할 사항에 포함되지 않는 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
변수에는 값의 범위, 선언 위치, 초기화가 중요하며 개발 화면 색상은 변수 선언과 무관하다.
13. 표현 가능한 최댓값을 넘어 더 큰 값이 되는 문제는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
자료형이 표현할 수 있는 상한을 벗어나는 현상을 오버플로라고 한다.
14. 함수 내부에 선언되어 그 함수에서 사용하는 변수는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
함수나 블록 안에서 선언한 변수는 지역변수이며 다른 함수의 같은 이름 변수와 별개이다.
15. 누적 합 변수 sum에 가장 적절한 초기값은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
합계를 누적하기 전 sum을 덧셈의 항등원인 0으로 초기화해야 올바른 결과를 얻는다.
16. 선행처리 지시어의 작성 규칙으로 옳지 않은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
선행처리 지시어의 끝에는 세미콜론을 사용하지 않는다.
17. 표준 디렉터리에서 헤더 파일을 찾는 형식은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
꺾쇠괄호를 사용한 include 형식은 표준 디렉터리에서 헤더 파일을 찾는다.
18. 정의한 매크로를 해제하는 지시어는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②#define으로 정의한 매크로는 #undef로 해제한다.
19. 매크로 함수의 인수와 수식에 괄호를 충분히 사용하는 주된 이유는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
매크로는 텍스트로 치환되므로 괄호가 없으면 전달한 식의 연산 순서가 의도와 달라질 수 있다.
20. 조건부 컴파일에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
조건부 컴파일은 실행 중 if문이 아니라 컴파일 전에 포함할 소스 코드를 결정하는 선행처리 기능이다.
댓글
댓글 쓰기