2강 · 제2장 · 약 70분
자료형과 선행처리기
상수·변수·자료형·ASCII·오버플로·열거형과 #include/#define/조건부 컴파일까지 PDF 없이도 익힙니다.
학습 목표
- 상수(정수·실수·문자·문자열)와 변수의 차이를 설명한다
- 기본 자료형의 크기·범위를 말하고 sizeof로 확인한다
- 대입(=)과 비교(==), 문자 코드와 문자열(\0)을 구분한다
- 오버플로·쓰레기 값·전역/지역(미리 보기)을 이해한다
- 선행처리기(#include, #define, 조건부 컴파일)와 매크로 괄호를 안다
- 교재 표기(void main, sizeof %d, long 크기)와 이 사이트 표기를 구분한다
왜 이 강이 필요한가?
프로그램은 명령과 자료로 이루어집니다.
같은 숫자라도 int에 담을지 double에 담을지에 따라 차지하는 메모리·표현 범위·연산 방식이 달라집니다.
2강에서는 “자료를 어떤 그릇에 담을지”와, 컴파일 직전에 소스를 가공하는 선행처리기를 익힙니다. PDF를 펼치지 않아도 이 페이지만으로 교재 제2장 핵심을 익힐 수 있게 구성했습니다.
1강에서 본 #include가 바로 선행처리입니다. 이번 강에서 그 이웃인 #define과 조건부 컴파일까지 이어집니다.
본문의 C 예제는 코드 아래에 실행 칸이 붙습니다. 교재처럼 조각만 있는 예제도 main과 출력이 채워지니 실행을 눌러 결과를 확인하세요.
1. 상수와 변수
자료형은 “자료를 담는 그릇”입니다. C에서는 그 자료를 상수와 변수로 나눕니다.
| 상수(constant) | 변수(variable) | |
|---|---|---|
| 의미 | 한 번 정해지면 바꾸지 않는 값 | 이름이 붙은 기억 공간. 실행 중 값이 바뀔 수 있음 |
| 예 | 10, 3.14, 'A', "hi", #define PI 3.14, const int N = 3 | int score = 0; score = 95; |
변수 특징 세 가지: 이름, 자료형, 저장된 값.
사용하려면 먼저 선언해서 컴파일러가 공간을 잡게 해야 합니다.
1.1 정수형 상수
| 표기 | 예 | 규칙 |
|---|---|---|
| 10진 | 10, -99 | 0~9, 0으로 시작하지 않음 |
| 8진 | 011, 055 | 앞에 0, 숫자는 0~7 |
| 16진 | 0x2A, 0XFF | 앞에 0x / 0X, AF (af와 같음) |
| unsigned | 12u, 0xFAu | 뒤에 u/U |
| long | 123456L, 0xFFL | 뒤에 l/L (대문자 L을 권장) |
같은 값이라도 표기만 다를 수 있습니다. 10진 104, 8진 0150, 16진 0x68은 모두 104입니다.
0x2a와 0x2A도 같습니다. A~F는 대소문자를 가리지 않습니다.
printf의 %d(부호 있는 정수), %u(unsigned), %ld(long)는 십진수로 보여 줍니다. 아래를 실행해 표의 예와 숫자를 맞춰 보세요. 리터럴을 바꿔 다시 실행해도 됩니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
앞에 0이 붙으면 8진수입니다. 011을 십진 11로 읽으면 안 됩니다.
1.2 실수형 상수
실수 리터럴의 기본 자료형은 보통 double 입니다.
| 방식 | 예 | 비고 |
|---|---|---|
| 소수 | 12.345, 3.14, .5 | 소수점 |
| 지수 | 12E3(=12000), 5e-2(=0.05) | e/E는 “×10의 거듭제곱” |
| float | 3.14f, 3.14F | 뒤에 f/F |
| long double | 3.14L | 뒤에 L |
지수 표기도 실행하면 평범한 십진 실수로 보입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
1.3 문자·문자열 상수
- 문자: 작은따옴표 하나 —
'A'
내부적으로는 ASCII 등 코드 값입니다.'A'≈ 65,'a'≈ 97,'0'≈ 48. - 문자열: 큰따옴표 —
"Hi"
끝에는 보이지 않는 널 문자\0이 붙습니다.
"AB"→A,B,\0(3칸)
"SEOUL KOREA"→ 글자 11개 +\0= 12칸 (가운데 공백 포함)
'A'(문자)와 "A"(문자열)는 다릅니다. 문자열은 최소 글자 + \0입니다.
문자 상수를 %d로 출력하면 코드 값(십진수) 이 나옵니다. 정수 0과 문자 '0'을 비교해 보세요.
이 예제 실행
실행 결과가 여기에 표시됩니다.
자주 쓰는 이스케이프 문자
| 표기 | 의미 |
|---|---|
\n | 줄바꿈 |
\t | 수평 탭 |
\r | 그 줄 맨 앞으로 |
\a | 경고음(환경에 따라 안 들릴 수 있음) |
\b | 백스페이스 |
\\ | 역슬래시 문자 |
\' | 작은따옴표 문자 |
\" | 큰따옴표 문자 |
\0 | 널(문자열 끝) |
1.4 변수 선언과 =의 의미
이 예제 실행
실행 결과가 여기에 표시됩니다.
C에서 = 는 “같다”가 아니라 대입(저장) 입니다.
“같은지 비교”는 == 입니다. (혼동하면 버그의 단골)
이름 규칙은 1강 식별자와 같습니다. 영문·숫자·밑줄, 숫자로 시작 불가, 예약어 불가, 대소문자 구분.
2. 자료형 — 그릇의 크기와 범위
자료형은 컴파일러에게 “이 이름으로 몇 바이트를 어떻게 해석할지” 알려 줍니다.
정수용인지, 실수를 담을지, 음수가 필요한지를 여기서 고릅니다.
교재는 자료형을 기본형(정수·실수·문자·열거형·void)과 확장형(배열·포인터·구조체 등, 이후 강)으로 나눕니다. 2강은 기본형에 집중합니다.
2.1 정수 자료형
int가 기본입니다. 앞에 short/long, signed/unsigned를 붙일 수 있습니다.
signed는 보통 생략합니다. int도 short/long 옆에서는 생략하는 경우가 있습니다 (unsigned short처럼).
같은 비트 수라도 unsigned는 음수를 포기하는 대신 양수 쪽 최댓값이 약 2배가 됩니다.
| 자료형(대표) | 전형적 크기 | 대략적 범위 |
|---|---|---|
short / signed short | 2바이트 | −32768 ~ 32767 |
unsigned short | 2바이트 | 0 ~ 65535 |
int / signed int | 흔히 4바이트 | 약 −21억 ~ 21억 |
unsigned int | 흔히 4바이트 | 0 ~ 약 42억 |
long | 4 또는 8바이트 | 환경에 따라 다름 |
long long | 8바이트 | 약 ±9×10¹⁸ |
unsigned long long | 8바이트 | 0 ~ 약 1.8×10¹⁹ |
크기는 컴퓨터·OS·컴파일러마다 다를 수 있습니다. 교재 표는 주로 Windows Visual C++ 기준입니다. 맥의 long은 흔히 8바이트라서 교재의 4바이트와 다를 수 있습니다. 확인은 항상 sizeof(타입).
범위의 상수 이름은 <limits.h>에 있습니다. INT_MAX, SHRT_MIN 등. 교재 예제 2-2처럼 직접 찍어 보면 내 컴퓨터의 실제 범위를 알 수 있습니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
2.2 실수 자료형
기본 실수는 double 입니다.
| 자료형 | 전형적 크기 | 대략적 범위(교재) |
|---|---|---|
float | 4바이트 | 약 3.4×10⁻³⁸ ~ 3.4×10³⁸ |
double | 8바이트 | 약 1.7×10⁻³⁰⁸ ~ 1.7×10³⁰⁸ |
long double | 8바이트 이상 | 환경에 따라 double과 같거나 더 큼 |
실수는 십진수를 있는 그대로 담지 않고, 부호·지수·가수로 나누어 2진 부동소수점(IEEE 754)으로 저장합니다. float은 단정밀도, double은 배정밀도입니다.
그래서 0.1 + 0.2가 딱 0.3이 안 되는 일이 생깁니다. “오차가 있는 근사값”으로 이해하세요.
2.3 문자형과 ASCII
char는 보통 1바이트. 문자를 정수 코드로 다룹니다.
| 자료형 | 전형적 범위 |
|---|---|
char (signed일 때) | −128 ~ 127 |
unsigned char | 0 ~ 255 |
자주 쓰는 코드: 'A'–'Z'는 65–90, 'a'–'z'는 97–122, '0'–'9'는 48–57.
교재의 ASCII 코드표에서 자주 나오는 값만 추리면 다음과 같습니다.
| 10진 | 문자 | 10진 | 문자 | |
|---|---|---|---|---|
| 0 | \0 (널) | 65 | A | |
| 9 | \t (탭) | 90 | Z | |
| 10 | \n (줄바꿈) | 97 | a | |
| 32 | 공백 | 122 | z | |
| 48 | 0 | 126 | ~ | |
| 57 | 9 | 127 | DEL |
0과 '0'은 다릅니다. 정수 0은 널에 가깝고, 문자 '0'의 코드는 48입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
%c는 문자로, %d는 코드 값(정수)으로 출력합니다.
2.4 열거형(enum) — 이름 붙인 정수
값이 요일처럼 몇 가지로 정해진 정수일 때, 숫자 대신 이름을 씁니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
첫 이름은 기본 0, 다음은 1씩 증가합니다. sun = 2처럼 시작값을 주면 그다음부터 3, 4, … 이므로 wed는 5입니다.
지금은 “읽기 쉬운 정수 상수 묶음” 정도로 알아 두고, 깊게 쓰는 것은 이후에도 충분합니다.
3. 변수 선언, 초기화, 오버플로
형식: 자료형 변수명;
예: int score;, float ratio;, char name[20]; (문자열은 글자 수 + 1을 \0용으로 잡는다는 뜻 — 8강에서 본격적으로)
선언할 때 볼 것 세 가지: 값의 크기(범위), 선언 위치, 초기화.
3.1 범위를 넘기면? (오버플로·언더플로)
그릇보다 큰 값·작은 값을 넣으면 오버플로/언더플로가 납니다. 컴파일이 될 수도 있고, 결과는 이상한 값으로 감싸질 수 있습니다.
교재 예: short 범위는 −32768 ~ 32767.
이 예제 실행
실행 결과가 여기에 표시됩니다.
같은 계산을 int에 담으면 32768, -32769가 그대로 나옵니다.
큰 수가 필요하면 자료형을 키우세요. short의 +1을 printf("%d", small + 1)로만 보면, +가 int로 승격되어 감싸짐이 안 보일 수 있습니다. 다시 short에 대입한 뒤 출력해 보세요.
3.2 선언 위치 (미리 보기)
- 함수 안 — 지역 변수. 그 함수가 실행될 때만 존재(스택). 자동으로 0이 되지 않음.
- 함수 밖 — 전역 변수. 프로그램이 켜져 있는 동안 존재. 보통 0으로 자동 초기화.
이름이 같으면 함수 안의 것이 그 함수에서는 바깥것을 가립니다. 자세한 규칙은 7강 기억 클래스에서 다룹니다. 입문에서는 되도록 main 안에 선언하고 초기화하는 습관이 안전합니다.
3.3 초기화와 쓰레기 값
지역 변수를 선언만 하고 값을 안 넣으면, 예전에 그 자리에 있던 쓰레기 값이 남아 있을 수 있습니다. Visual Studio는 초기화하지 않은 사용을 에러로 잡기도 합니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
입문에서는 선언과 동시에 초기화하세요.
4. 선행처리기 (Preprocessor)
실행 파일을 만들 때 순서는 1강과 같습니다.
선행처리 → 컴파일 → 링킹
선행처리기는 컴파일 직전에 #로 시작하는 지시문을 처리합니다.
공통 규칙
- 줄은
#로 시작 - 끝에 세미콜론 없음
- 한 줄에 하나 (길면 줄 끝에
\로 이어 쓰기) - 보통 파일 맨 위(도입부)
| 지시문 | 역할 |
|---|---|
#include | 파일 포함 |
#define / #undef | 매크로 정의 / 해제 |
#if #ifdef #else #endif | 조건부 컴파일 |
4.1 #include — 파일 포함
| 형식 | 찾는 위치(개념) |
|---|---|
#include <stdio.h> | 표준(시스템) 헤더 경로 |
#include "my.h" | 현재/지정 경로의 사용자 헤더 우선 |
stdio.h를 포함해야 printf 등의 선언(원형) 을 쓸 수 있습니다. 구현은 링크 때 붙습니다.
자주 보는 헤더
| 헤더 | 용도 |
|---|---|
stdio.h | 표준 입출력 (printf, scanf) |
stdlib.h | 변환, 메모리 할당 등 |
string.h | 문자열 |
math.h | 수학 함수 |
ctype.h | 문자 종류 검사 |
time.h | 시간 |
limits.h | 정수 자료형 최솟값·최댓값 |
사용자 헤더(.h)는 여러 .c가 같이 쓰는 #define·함수 원형을 모아 두는 용도입니다. 이 사이트 실행기는 한 파일만 컴파일하므로, #include "my.h" 실습은 로컬에서 두 파일로 하는 편이 맞습니다.
4.2 #define — 매크로
컴파일 전에 이름이 텍스트로 치환됩니다. 진짜 변수도, 진짜 함수도 아닙니다.
매크로 상수
이 예제 실행
실행 결과가 여기에 표시됩니다.
- 이름은 보통 대문자
- 끝 세미콜론 없음 (붙이면 세미콜론까지 치환에 들어갑니다)
- 여러 줄이면 줄 끝에
\ - 해제:
#undef ADDR
문장 전체도 치환 대상이 됩니다. 교재 예제 2-2는 #define OUT printf("...\n") 처럼 출력문 하나에 이름을 붙여 씁니다(가독성을 위한 것일 뿐, 권장하는 방식은 아닙니다).
매크로 “함수” — 단순 치환
이 예제 실행
실행 결과가 여기에 표시됩니다.
인자·전체에 괄호를 꼭 쓰세요.
이 예제 실행
실행 결과가 여기에 표시됩니다.
10 * HAP(3,4)→10 * 3 + 4= 34 (70이 아님)GOP(1+2, 3+4)→1 + 2 * 3 + 4= 11 (21이 아님)
괄호가 있으면 10 * ((3)+(4)) = 70, ((1+2)*(3+4)) = 21.
장점: 자료형을 안 가리고, 한두 줄이면 함수 호출보다 가벼울 수 있습니다.
입문에서 바뀌면 안 되는 값은 #define 또는 const 둘 다 가능하고, 타입 검사가 필요하면 const가 유리한 경우가 많습니다.
4.3 조건부 컴파일
#if / #ifdef / #elif / #else / #endif로 어떤 코드를 컴파일에 넣을지 고릅니다.
조건은 실행 중 변수가 아니라, 선행처리 시점에 알 수 있는 매크로 값이어야 합니다. 4강의 if와 겉모습은 비슷하지만, 여기는 “컴파일에 넣을지 말지”입니다.
이 예제 실행
실행 결과가 여기에 표시됩니다.
DEBUG가 1이면 debug on 줄만 남고, else 쪽은 없는 코드가 됩니다.
교재 예제와 이 사이트가 다른 점
| 교재에서 자주 보임 | 이 사이트 | 이유 |
|---|---|---|
void main() | int main(void) | 1강과 같음. 표준 권장 형태 |
sizeof를 %d로 출력 | %zu (또는 값을 int로 캐스트) | sizeof의 결과는 int가 아님. 맥·64비트에서 %d는 경고가 날 수 있음 |
long = 4바이트 | 맥에서는 흔히 8바이트 | sizeof(long)으로 확인 |
사용자 헤더 exam2-3.h | 실행기는 단일 파일 | 로컬에서 .h + .c로 연습 |
5. 지금 실습할 것
위 본문 예제는 각 블록에서 이미 실행해 볼 수 있습니다.
아래는 상수·sizeof·매크로·오버플로를 한 파일에 모은 종합 실습입니다.
아래 코드에서:
- 그대로 실행해 출력·
sizeof·ASCII 확인 year값을 바꾸고 다시 실행#define COURSE문자열을 수정해 보기10 * HAP_BAD(3,4)가 70이 아닌 이유를 본문과 맞춰 보기short에 최댓값+1을 대입한 뒤 출력해 감싸짐을 관찰- (선택)
'A'를'B'로 바꿔%c와%d가 어떻게 변하는지 보기 - 1.1 예제에서
0x68을0xFF로 바꿔 십진수가 255인지 확인
printf 형식 미리보기: %d 정수, %ld/%lld long, %f/%.2f 실수, %c 문자, %s 문자열, %zu는 sizeof에 자주 사용합니다. (3강에서 입출력 형식을 더 다룹니다.)
코드 실습 (C)
실행 결과가 여기에 표시됩니다.