프로그래밍/C,C++

코드 최적화 - if-else나 switch-case 대신 배열 인덱스 활용하기

채윤아빠 2024. 7. 25. 08:39

개념

조건문(if-else, switch-case)은 분기 예측(branch prediction)에 의존하며, 예측이 틀릴 경우 CPU 파이프라인 플러시가 발생하여 성능이 저하됩니다. 배열 인덱싱은 조건 분기 없이 직접 값에 접근합니다.

문제점

  • 조건문은 CPU 분기 예측 실패 시 성능 저하
  • 여러 조건을 순차적으로 평가하는 비용
  • 코드 크기 증가 및 명령어 캐시 효율성 감소

최적화 방법

  1. 룩업 테이블(Lookup Table) 사용: 가능한 모든 결과를 배열에 미리 저장
  2. 함수 포인터 배열: 다양한 동작을 함수 포인터 배열로 구현
  3. 비트 마스킹과 배열 조합: 복잡한 조건을 비트 연산과 배열로 대체

예시

// 비효율적인 방법 (switch-case)
int getActionValue(int action) {
    switch (action) {
        case 0: return 100;
        case 1: return 200;
        case 2: return 300;
        case 3: return 400;
        default: return 500;
    }
}

// 최적화된 방법 (배열 인덱싱)
int getActionValue(int action) {
    static const int values[] = {100, 200, 300, 400, 500};
    return (action >= 0 && action < 4) ? values[action] : values[4];
}

 

함수 포인터 배열 예시

typedef void (*ActionFunc)(void);

void action0() { /* 동작 0 */ }
void action1() { /* 동작 1 */ }
void action2() { /* 동작 2 */ }

// 최적화된 방법
void executeAction(int action) {
    static const ActionFunc actions[] = {action0, action1, action2};
    if (action >= 0 && action < 3) {
        actions[action]();
    }
}

성능 향상 이유

  • 분기 예측 실패 회피
  • 메모리 접근 패턴 단순화
  • 명령어 파이프라인 효율성 향상
  • 코드 크기 감소 가능

추가 고려사항

  • 배열 크기가 크면 메모리 사용량 증가
  • 인덱스 범위 검사 필수
  • 희소 데이터(sparse data)의 경우 해시맵 고려하기

맺는말

간단하지만 위와 같은 배열 인덱스 활용하기를 적용하면 특히 임베디드 시스템, 게임 엔진, 고성능 서버 등 성능이 중요한 애플리케이션에서 큰 차이를 만들 수 있습니다. 하지만 항상 가독성과 유지보수성을 함께 고려해야 합니다.



728x90
반응형