프로그래밍 언어별 흔한 에러 해결 가이드 | C++, Python, Java, JavaScript

프로그래밍 언어별 흔한 에러 해결 가이드 | C++, Python, Java, JavaScript

이 글의 핵심

프로그래밍 언어별 흔한 에러 해결 가이드입니다. 컴파일 에러, 런타임 에러, 논리 에러를 체계적으로 해결하는 방법을 제시합니다.

들어가며: 에러는 배움의 기회

”에러 메시지가 무슨 뜻인지 모르겠어요”

프로그래밍을 하다 보면 수많은 에러를 만나게 됩니다. 에러는 버그가 아니라 컴파일러나 런타임이 보내는 힌트입니다.

이 글에서 다루는 것:

  • 언어별 흔한 에러와 해결법
  • 에러 메시지 읽는 법
  • 체계적인 디버깅 방법
  • 예방 전략

목차

  1. C++ 흔한 에러
  2. Python 흔한 에러
  3. Java 흔한 에러
  4. JavaScript 흔한 에러
  5. 디버깅 전략
  6. 정리

1. C++ 흔한 에러

1.1 Segmentation Fault (세그멘테이션 폴트)

에러 메시지:

Segmentation fault (core dumped)

원인:

  • 널 포인터 역참조
  • 배열 범위 초과
  • 해제된 메모리 접근
  • 스택 오버플로

예제:

// 원인 1: 널 포인터 역참조
int* ptr = nullptr;
*ptr = 10;  // ❌ Segmentation fault

// 해결
if (ptr != nullptr) {
    *ptr = 10;
}

// 원인 2: 배열 범위 초과
int arr[5] = {1, 2, 3, 4, 5};
arr[10] = 100;  // ❌ 미정의 동작, Segfault 가능

// 해결: vector 사용 (at()으로 범위 체크)
std::vector<int> vec = {1, 2, 3, 4, 5};
try {
    vec.at(10) = 100;  // ✅ 예외 발생
} catch (const std::out_of_range& e) {
    std::cerr << "범위 초과: " << e.what() << std::endl;
}

// 원인 3: 댕글링 포인터 (해제된 메모리 접근)
int* ptr2 = new int(10);
delete ptr2;
*ptr2 = 20;  // ❌ 이미 해제된 메모리

// 해결: 스마트 포인터 사용
std::unique_ptr<int> smart_ptr = std::make_unique<int>(10);
// 자동 해제, 댕글링 포인터 방지

디버깅 도구:

# GDB로 디버깅
g++ -g main.cpp -o main
gdb ./main
(gdb) run
(gdb) backtrace  # 크래시 위치 확인

# Valgrind로 메모리 에러 검사
valgrind --leak-check=full ./main

# AddressSanitizer (ASan)
g++ -fsanitize=address -g main.cpp -o main
./main

1.2 Undefined Reference (링커 에러)

에러 메시지:

undefined reference to `myFunction()'

원인:

  • 함수 선언만 있고 정의가 없음
  • 라이브러리 링크 누락
  • 네임스페이스 불일치

예제:

// header.h
void myFunction();

// main.cpp
#include "header.h"
int main() {
    myFunction();  // ❌ undefined reference
    return 0;
}

// 해결: 정의 추가
// impl.cpp
#include "header.h"
void myFunction() {
    // 구현
}

// 컴파일
g++ main.cpp impl.cpp -o main  // ✅

라이브러리 링크 누락:

# 에러
g++ main.cpp -o main
# undefined reference to `pthread_create'

# 해결: -lpthread 추가
g++ main.cpp -o main -lpthread

1.3 Template 에러

에러 메시지:

error: no matching function for call to 'std::vector<int>::push_back(std::string)'

원인: 템플릿 타입 불일치

예제:

std::vector<int> vec;
vec.push_back("hello");  // ❌ 타입 에러

// 해결
std::vector<std::string> vec;
vec.push_back("hello");  // ✅

2. Python 흔한 에러

2.1 IndentationError

에러 메시지:

IndentationError: expected an indented block

원인: 들여쓰기 불일치

예제:

# ❌ 에러
def greet():
print("Hello")  # 들여쓰기 없음

# ✅ 해결
def greet():
    print("Hello")

# ❌ 탭과 스페이스 혼용
def calculate():
    x = 10  # 스페이스 4칸
	y = 20  # 탭 1개
    return x + y  # IndentationError

# ✅ 해결: 스페이스로 통일
def calculate():
    x = 10
    y = 20
    return x + y

예방:

  • 에디터 설정: 스페이스 4칸
  • .editorconfig 사용
# .editorconfig
[*.py]
indent_style = space
indent_size = 4

2.2 NameError

에러 메시지:

NameError: name 'x' is not defined

원인: 변수를 정의하기 전에 사용

예제:

# ❌ 에러
print(x)  # x가 정의되지 않음

# ✅ 해결
x = 10
print(x)

# ❌ 함수 내부에서 전역 변수 수정
count = 0
def increment():
    count += 1  # UnboundLocalError

# ✅ 해결: global 키워드
count = 0
def increment():
    global count
    count += 1

2.3 TypeError

에러 메시지:

TypeError: unsupported operand type(s) for +: 'int' and 'str'

원인: 타입 불일치

예제:

# ❌ 에러
result = 10 + "20"  # int + str

# ✅ 해결
result = 10 + int("20")  # 30
result = str(10) + "20"  # "1020"

# ❌ None 타입 연산
def get_value():
    return None

x = get_value()
y = x + 10  # TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

# ✅ 해결: None 체크
x = get_value()
if x is not None:
    y = x + 10

2.4 IndexError

에러 메시지:

IndexError: list index out of range

원인: 리스트 범위 초과

예제:

# ❌ 에러
arr = [1, 2, 3]
print(arr[5])  # IndexError

# ✅ 해결: 범위 체크
if len(arr) > 5:
    print(arr[5])
else:
    print("인덱스 범위 초과")

# ✅ 또는 try-except
try:
    print(arr[5])
except IndexError:
    print("인덱스 범위 초과")

3. Java 흔한 에러

3.1 NullPointerException

에러 메시지:

java.lang.NullPointerException

원인: null 객체의 메서드 호출

예제:

// ❌ 에러
String str = null;
int len = str.length();  // NullPointerException

// ✅ 해결: null 체크
String str = null;
if (str != null) {
    int len = str.length();
}

// ✅ Java 8+ Optional 사용
Optional<String> opt = Optional.ofNullable(str);
int len = opt.map(String::length).orElse(0);

// ✅ Java 14+ 패턴 매칭
if (str instanceof String s) {
    int len = s.length();
}

3.2 ClassCastException

에러 메시지:

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

원인: 잘못된 타입 캐스팅

예제:

// ❌ 에러
Object obj = "Hello";
Integer num = (Integer) obj;  // ClassCastException

// ✅ 해결: instanceof 체크
Object obj = "Hello";
if (obj instanceof Integer) {
    Integer num = (Integer) obj;
} else {
    System.out.println("Integer가 아닙니다");
}

// ✅ 제네릭 사용 (타입 안전)
List<Integer> list = new ArrayList<>();
list.add(10);
Integer num = list.get(0);  // 캐스팅 불필요

3.3 ConcurrentModificationException

에러 메시지:

java.util.ConcurrentModificationException

원인: 순회 중 컬렉션 수정

예제:

// ❌ 에러
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
for (Integer num : list) {
    if (num % 2 == 0) {
        list.remove(num);  // ConcurrentModificationException
    }
}

// ✅ 해결: Iterator 사용
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
    Integer num = it.next();
    if (num % 2 == 0) {
        it.remove();
    }
}

// ✅ 또는 removeIf 사용 (Java 8+)
list.removeIf(num -> num % 2 == 0);

4. JavaScript 흔한 에러

4.1 TypeError: Cannot read property of undefined

에러 메시지:

TypeError: Cannot read property 'name' of undefined

원인: undefined 객체의 속성 접근

예제:

// ❌ 에러
const user = undefined;
console.log(user.name);  // TypeError

// ✅ 해결: Optional Chaining (ES2020)
console.log(user?.name);  // undefined (에러 안 남)

// ✅ 기본값 설정
const name = user?.name ?? 'Guest';
console.log(name);  // 'Guest'

// ✅ 명시적 체크
if (user && user.name) {
    console.log(user.name);
}

4.2 ReferenceError: x is not defined

에러 메시지:

ReferenceError: x is not defined

원인: 선언되지 않은 변수 사용

예제:

// ❌ 에러
console.log(x);  // ReferenceError

// ✅ 해결
const x = 10;
console.log(x);

// ❌ 호이스팅 문제
console.log(y);  // undefined (var는 호이스팅)
var y = 10;

// ✅ let/const 사용 (TDZ)
console.log(z);  // ReferenceError
const z = 10;

4.3 Promise 에러

에러 메시지:

UnhandledPromiseRejectionWarning: Error: Failed to fetch

원인: Promise rejection 미처리

예제:

// ❌ 에러 (catch 없음)
fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(data => console.log(data));
// 네트워크 에러 시 UnhandledPromiseRejection

// ✅ 해결: catch 추가
fetch('https://api.example.com/data')
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => console.error('에러:', err));

// ✅ async/await 사용
async function fetchData() {
  try {
    const res = await fetch('https://api.example.com/data');
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error('에러:', err);
  }
}

4.4 this 바인딩 문제

에러 메시지:

TypeError: Cannot read property 'name' of undefined

원인: this가 예상과 다른 객체를 가리킴

예제:

// ❌ 에러
class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet() {
    console.log(`Hello, ${this.name}`);
  }
}

const person = new Person('Alice');
setTimeout(person.greet, 1000);  // TypeError: this is undefined

// ✅ 해결 1: 화살표 함수
setTimeout(() => person.greet(), 1000);

// ✅ 해결 2: bind
setTimeout(person.greet.bind(person), 1000);

// ✅ 해결 3: 클래스 필드 (화살표 함수)
class Person {
  constructor(name) {
    this.name = name;
  }
  
  greet = () => {
    console.log(`Hello, ${this.name}`);
  }
}

5. 디버깅 전략

체계적 디버깅 프로세스

flowchart TD
    A[에러 발생] --> B[에러 메시지 읽기]
    B --> C{컴파일 에러?}
    C -->|예| D[문법/타입 체크]
    C -->|아니오| E{런타임 에러?}
    E -->|예| F[스택 트레이스 확인]
    E -->|아니오| G[논리 에러]
    
    D --> H[에러 위치 수정]
    F --> I[디버거로 추적]
    G --> J[로그/테스트 추가]
    
    H --> K[재컴파일]
    I --> L[원인 파악]
    J --> L
    L --> M[수정 및 테스트]

디버깅 도구 비교

언어디버거로깅테스트
C++GDB, LLDB, Visual Studio Debuggerspdlog, glogGoogle Test, Catch2
Pythonpdb, ipdblogging, logurupytest, unittest
JavaIntelliJ Debugger, jdbLog4j, SLF4JJUnit, TestNG
JavaScriptChrome DevTools, VS Codeconsole, winstonJest, Mocha

디버깅 팁

1. 에러 메시지를 정확히 읽기

❌ "에러가 났어요" (너무 모호)
✅ "TypeError: Cannot read property 'name' of undefined at line 42" (구체적)

2. 최소 재현 코드 만들기

// 복잡한 코드에서 에러 발생
// → 최소한의 코드로 재현

// 원본 (100줄)
function complexFunction() {
  // ... 복잡한 로직
  const result = data.map(x => x.value).filter(x => x > 10);
  // ... 더 복잡한 로직
}

// 최소 재현 (5줄)
const data = [{ value: 5 }, { value: 15 }];
const result = data.map(x => x.value).filter(x => x > 10);
console.log(result);  // [15]

3. 이분 탐색으로 원인 찾기

# 코드가 100줄인데 어디서 에러가 나는지 모름
# → 절반씩 주석 처리하며 범위 좁히기

# 1-50줄 주석 → 에러 안 남 → 1-50줄에 원인
# 1-25줄 주석 → 에러 남 → 26-50줄에 원인
# 26-37줄 주석 → 에러 안 남 → 26-37줄에 원인
# ...

4. 로그 추가

// C++
#include <iostream>
void process(int x) {
    std::cout << "DEBUG: x = " << x << std::endl;
    // ... 로직
}
# Python
import logging
logging.basicConfig(level=logging.DEBUG)

def process(x):
    logging.debug(f"x = {x}")
    # ... 로직

5. 디버거 사용

# Python pdb
python -m pdb script.py

# Node.js
node --inspect-brk script.js
# Chrome에서 chrome://inspect 열기

6. 정리

핵심 요약

C++ 흔한 에러:

  • Segmentation Fault: 메모리 접근 에러
  • Undefined Reference: 링커 에러
  • Template 에러: 타입 불일치

Python 흔한 에러:

  • IndentationError: 들여쓰기 불일치
  • NameError: 변수 미정의
  • TypeError: 타입 불일치

Java 흔한 에러:

  • NullPointerException: null 접근
  • ClassCastException: 잘못된 캐스팅
  • ConcurrentModificationException: 순회 중 수정

JavaScript 흔한 에러:

  • TypeError: undefined 접근
  • ReferenceError: 변수 미정의
  • Promise rejection: 비동기 에러 미처리

디버깅 체크리스트

  • 에러 메시지 정확히 읽기
  • 스택 트레이스 확인
  • 최소 재현 코드 만들기
  • 로그 추가
  • 디버거 사용
  • 테스트 코드 작성

다음 단계

각 언어의 자세한 디버깅 방법은 아래 글을 참고하세요:

  • C++ 크래시 디버깅
  • Python 디버깅
  • JavaScript 디버깅

관련 주제:

  • 단위 테스트 작성법
  • 로깅 전략
  • 에러 처리 패턴