컴파일과 런타임의 차이
요약
컴파일 시점과 런타임 시점의 차이를 알아봅니다. C, Java, Python 공통 개념으로, 메모리 구조와 동적 메모리 할당을 이해하기 위한 필수 배경 지식입니다.
핵심 정리
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 시점 | 소스 코드 → 실행 파일 변환 시 | 프로그램 실행 중 |
| 결정되는 것 | 배열 크기, 지역 변수 크기, 타입 | malloc 크기, 사용자 입력 |
| 오류 | 문법 오류, 타입 오류 | 0으로 나누기, 널 포인터 접근 |
핵심 정리
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 시점 | 소스 코드 → 바이트코드 변환 시 | 프로그램 실행 중 |
| 결정되는 것 | 변수 타입, 오버로딩, 제네릭 타입 소거 | 사용자 입력, 오버라이딩 |
| 오류 | 문법 오류, 타입 오류 | NullPointerException, ArrayIndexOutOfBounds |
핵심 정리
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 시점 | 소스 코드 → 바이트코드 변환 시 | 프로그램 실행 중 |
| 결정되는 것 | 문법 검사 | 타입, 변수, 리스트 크기 등 거의 모든 것 |
| 오류 | SyntaxError | TypeError, IndexError, NameError 등 |
컴파일이란? 쌩기초
컴파일(Compile) 은 사람이 작성한 소스 코드를 컴퓨터가 이해할 수 있는 형태로 변환하는 과정입니다.
위 코드를 컴파일하면 실행 가능한 파일이 생성됩니다.
Java는 소스 코드를 바이트코드로 컴파일하고, JVM(Java Virtual Machine)이 실행합니다.
컴파일 과정에서 Java의 제네릭 타입 소거도 발생합니다. <T>로 선언한 타입 정보가 .class 파일에서는 Object로 바뀝니다.
Python은 인터프리터 언어로 불리지만, 실행 전에 내부적으로 바이트코드(.pyc)로 변환하는 과정을 거칩니다.
C나 Java와 달리 별도의 컴파일 명령이 필요 없습니다. 하지만 실행 전에 문법 검사(SyntaxError) 가 이루어지므로, 이 단계를 Python의 컴파일이라고 볼 수 있습니다.
런타임이란? 쌩기초
런타임(Runtime) 은 프로그램이 실제로 실행되는 시점을 의미합니다.
| 단계 | 설명 |
|---|---|
| 1. 작성 | 소스 코드 작성 (.c 파일) |
| 2. 컴파일 | 소스 코드 → 실행 파일 변환 |
| 3. 런타임 | 실행 파일을 실행하는 시점 |
런타임에는 사용자 입력을 받거나, 파일을 읽거나, 네트워크 통신을 하는 등 실행 중에만 알 수 있는 일들이 발생합니다.
| 단계 | 설명 |
|---|---|
| 1. 작성 | 소스 코드 작성 (.java 파일) |
| 2. 컴파일 | 소스 코드 → 바이트코드 변환 (.class) |
| 3. 런타임 | JVM이 .class 파일을 실행하는 시점 |
런타임에는 사용자 입력을 받거나, 파일을 읽거나, 네트워크 통신을 하는 등 실행 중에만 알 수 있는 일들이 발생합니다.
| 단계 | 설명 |
|---|---|
| 1. 작성 | 소스 코드 작성 (.py 파일) |
| 2. 컴파일 | 문법 검사 + 바이트코드 변환 (.pyc) |
| 3. 런타임 | 바이트코드를 실행하는 시점 |
Python에서는 컴파일과 런타임이 거의 동시에 일어나지만, 개념적으로는 구분됩니다. 런타임에는 사용자 입력을 받거나, 파일을 읽거나, 네트워크 통신을 하는 등 실행 중에만 알 수 있는 일들이 발생합니다.
컴파일 시점에 결정되는 것 기초
컴파일러가 코드를 분석할 때 미리 알 수 있는 것들입니다.
1. 배열 크기
배열 크기는 컴파일 시점에 상수로 지정해야 합니다.
2. 지역 변수 크기
함수 호출 시 스택에 얼마만큼의 공간이 필요한지 컴파일러가 미리 계산합니다.
3. 자료형 크기
sizeof 연산자의 결과값은 컴파일 시점에 확정됩니다. 자료형마다 크기가 정해져 있기 때문입니다.
1. 변수 타입
Java는 정적 타입 언어입니다. 변수의 타입은 컴파일 시점에 결정됩니다.
2. 오버로딩 메서드 선택
오버로딩된 메서드 중 어떤 것을 호출할지는 컴파일 시점에 매개변수 타입으로 결정됩니다.
3. 제네릭 타입 소거
제네릭의 타입 파라미터 T는 컴파일 후 Object로 바뀝니다.
이 때문에 오버로딩과 함께 출제되면 예상과 다른 결과가 나옵니다. 자세한 내용은 제네릭과 타입 소거를 참고하세요.
Python의 컴파일 시점에는 문법 검사만 이루어집니다. 타입, 변수 존재 여부 등은 런타임에 확인됩니다.
문법 검사
런타임에 결정되는 것 기초
프로그램 실행 중에만 알 수 있는 것들입니다.
1. malloc 크기
위 코드에서 malloc은 프로그램 실행 중에 메모리를 빌려오는 함수입니다. 사용자가 n에 어떤 값을 입력하느냐에 따라 빌려오는 메모리 크기가 달라지므로, 컴파일 시점에는 크기를 알 수 없습니다. 자세한 내용은 동적 메모리 할당에서 다룹니다.
2. 사용자 입력
3. 조건문 결과
조건문의 결과는 실행 중에 변수의 값이 정해져야 알 수 있습니다.
4. 파일 내용
1. 사용자 입력
2. 오버라이딩 메서드 선택
오버라이딩된 메서드는 런타임에 실제 객체의 타입을 보고 결정됩니다.
3. 조건문 결과
4. ArrayList 크기
Python에서는 거의 모든 것이 런타임에 결정됩니다.
1. 변수 타입
Python은 변수를 선언할 때 타입을 지정하지 않습니다. 값을 대입하는 순간 타입이 결정되고, 다른 타입의 값을 다시 대입할 수도 있습니다.
2. 리스트 크기
3. 변수 존재 여부
4. 사용자 입력
컴파일 에러 vs 런타임 에러 기초
컴파일 에러
컴파일 에러는 컴파일 과정에서 발견되는 오류입니다. 프로그램이 아예 실행 파일로 만들어지지 않습니다.
| 컴파일 에러 종류 | 예시 |
|---|---|
| 문법 오류 | 세미콜론 누락, 괄호 불일치 |
| 타입 불일치 | int에 char* 대입 |
| 선언되지 않은 변수 | prinft (오타) |
| 잘못된 연산 | 10 + "hello" |
런타임 에러
런타임 에러는 프로그램 실행 중에 발생하는 오류입니다. 컴파일은 성공했지만 실행 중에 문제가 생깁니다.
컴파일 에러
컴파일 에러는 컴파일 과정에서 발견되는 오류입니다. .class 파일이 생성되지 않습니다.
| 컴파일 에러 종류 | 예시 |
|---|---|
| 문법 오류 | 세미콜론 누락, 괄호 불일치 |
| 타입 불일치 | int에 String 대입 |
| 선언되지 않은 변수 | 미선언 변수 사용 |
| 접근 제어 위반 | private 메서드 외부 호출 |
런타임 에러
런타임 에러는 프로그램 실행 중에 발생하는 오류(예외)입니다. 컴파일은 성공했지만 실행 중에 문제가 생깁니다.
| 런타임 에러 종류 | 예외 클래스 |
|---|---|
| 0으로 나누기 | ArithmeticException |
| null 참조 | NullPointerException |
| 배열 범위 초과 | ArrayIndexOutOfBoundsException |
| 잘못된 형변환 | ClassCastException |
| 스택 오버플로우 | StackOverflowError |
컴파일 에러 (SyntaxError)
Python에서 컴파일 시점에 발생하는 오류는 SyntaxError뿐입니다. 코드가 실행되기 전에 잡힙니다.
런타임 에러
Python의 대부분 오류는 런타임에 발생합니다. 문법은 맞지만 실행 중에 문제가 생기는 경우입니다.
| 런타임 에러 종류 | 예외 클래스 |
|---|---|
| 0으로 나누기 | ZeroDivisionError |
| 존재하지 않는 변수 | NameError |
| 타입 불일치 | TypeError |
| 인덱스 범위 초과 | IndexError |
| 속성 없음 | AttributeError |
정리: 컴파일 vs 런타임 기초
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 언제 | 코드 → 실행 파일 변환 시 | 프로그램 실행 중 |
| 메모리 할당 | 스택 변수, 배열 크기 | malloc, 동적 배열 |
| 오류 발견 | 문법, 타입 오류 | 논리 오류, 예외 상황 |
| 오류 시 | 실행 파일 생성 안 됨 | 프로그램 비정상 종료 |
이 개념을 이해하면 메모리 구조에서 스택과 힙의 차이, 동적 메모리 할당에서 malloc이 필요한 이유를 더 잘 이해할 수 있습니다.
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 언제 | 코드 → 바이트코드 변환 시 | JVM이 프로그램 실행 중 |
| 결정 | 변수 타입, 오버로딩, 타입 소거 | 오버라이딩, 사용자 입력 |
| 오류 발견 | 문법, 타입 오류 | 예외 (Exception) |
| 오류 시 | .class 파일 생성 안 됨 | 예외 발생, 프로그램 종료 |
오버로딩과 오버라이딩의 결정 시점 차이는 오버로딩에서 자세히 다룹니다.
| 구분 | 컴파일 시점 | 런타임 시점 |
|---|---|---|
| 언제 | 코드 → 바이트코드 변환 시 | 바이트코드 실행 중 |
| 검사 | 문법 검사만 | 타입, 변수, 연산 등 모든 것 |
| 오류 | SyntaxError | TypeError, NameError, IndexError 등 |
| 오류 시 | 프로그램 실행 안 됨 | 해당 줄에서 프로그램 종료 |
Python은 동적 타입 언어이므로 C나 Java보다 런타임에 결정되는 것이 훨씬 많습니다. 이 때문에 코드를 실행해봐야 오류를 발견할 수 있는 경우가 대부분입니다.