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 = 3int score = 0; score = 95;

변수 특징 세 가지: 이름, 자료형, 저장된 값.
사용하려면 먼저 선언해서 컴파일러가 공간을 잡게 해야 합니다.

1.1 정수형 상수

표기예규칙
10진10, -990~9, 0으로 시작하지 않음
8진011, 055앞에 0, 숫자는 0~7
16진0x2A, 0XFF앞에 0x / 0X, AF (af와 같음)
unsigned12u, 0xFAu뒤에 u/U
long123456L, 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의 거듭제곱”
float3.14f, 3.14F뒤에 f/F
long double3.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 short2바이트−32768 ~ 32767
unsigned short2바이트0 ~ 65535
int / signed int흔히 4바이트약 −21억 ~ 21억
unsigned int흔히 4바이트0 ~ 약 42억
long4 또는 8바이트환경에 따라 다름
long long8바이트약 ±9×10¹⁸
unsigned long long8바이트0 ~ 약 1.8×10¹⁹

크기는 컴퓨터·OS·컴파일러마다 다를 수 있습니다. 교재 표는 주로 Windows Visual C++ 기준입니다. 맥의 long은 흔히 8바이트라서 교재의 4바이트와 다를 수 있습니다. 확인은 항상 sizeof(타입).

범위의 상수 이름은 <limits.h>에 있습니다. INT_MAX, SHRT_MIN 등. 교재 예제 2-2처럼 직접 찍어 보면 내 컴퓨터의 실제 범위를 알 수 있습니다.

이 예제 실행

실행 결과가 여기에 표시됩니다.

2.2 실수 자료형

기본 실수는 double 입니다.

자료형전형적 크기대략적 범위(교재)
float4바이트약 3.4×10⁻³⁸ ~ 3.4×10³⁸
double8바이트약 1.7×10⁻³⁰⁸ ~ 1.7×10³⁰⁸
long double8바이트 이상환경에 따라 double과 같거나 더 큼

실수는 십진수를 있는 그대로 담지 않고, 부호·지수·가수로 나누어 2진 부동소수점(IEEE 754)으로 저장합니다. float은 단정밀도, double은 배정밀도입니다.
그래서 0.1 + 0.2가 딱 0.3이 안 되는 일이 생깁니다. “오차가 있는 근사값”으로 이해하세요.

2.3 문자형과 ASCII

char는 보통 1바이트. 문자를 정수 코드로 다룹니다.

자료형전형적 범위
char (signed일 때)−128 ~ 127
unsigned char0 ~ 255

자주 쓰는 코드: 'A'–'Z'는 65–90, 'a'–'z'는 97–122, '0'–'9'는 48–57.

교재의 ASCII 코드표에서 자주 나오는 값만 추리면 다음과 같습니다.

10진문자10진문자
0\0 (널)65A
9\t (탭)90Z
10\n (줄바꿈)97a
32공백122z
480126~
579127DEL

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·매크로·오버플로를 한 파일에 모은 종합 실습입니다.

아래 코드에서:

  1. 그대로 실행해 출력·sizeof·ASCII 확인
  2. year 값을 바꾸고 다시 실행
  3. #define COURSE 문자열을 수정해 보기
  4. 10 * HAP_BAD(3,4)가 70이 아닌 이유를 본문과 맞춰 보기
  5. short에 최댓값+1을 대입한 뒤 출력해 감싸짐을 관찰
  6. (선택) 'A'를 'B'로 바꿔 %c와 %d가 어떻게 변하는지 보기
  7. 1.1 예제에서 0x68을 0xFF로 바꿔 십진수가 255인지 확인

printf 형식 미리보기: %d 정수, %ld/%lld long, %f/%.2f 실수, %c 문자, %s 문자열, %zu는 sizeof에 자주 사용합니다. (3강에서 입출력 형식을 더 다룹니다.)

코드 실습 (C)

실행 결과가 여기에 표시됩니다.

확인 퀴즈

1. 실행 중에 값이 바뀔 수 있는 기억 공간에 이름을 붙인 것은?
2. C에서 a = 10; 의 = 의미로 바른 것은?
3. 8진 상수 0150과 16진 상수 0x68의 10진 값은?
4. 문자열 "AB"가 메모리에 저장될 때 끝에 붙는 것은?
5. 문자 '0'과 정수 0의 차이로 가장 알맞은 것은?
6. short 최댓값 32767에 1을 더해 다시 short에 저장하면 흔히 어떻게 되나?
7. 선행처리기는 언제 동작하는가?
8. #include <stdio.h>와 #include "my.h"의 차이에 가까운 설명은?
9. 매크로 #define HAP(x,y) x+y 일 때 10 * HAP(3,4)가 위험할 수 있는 이유는?

스스로 점검