앤디 블로그
  • 모두
  • 개발 문화
  • 기술
  • 자바
  • 스프링
  • 인프라
  • 카프카
  • 데이터베이스
  • 컨퍼런스
책
짧은 글
이력서
  • 모두
  • 개발 문화
  • 기술
  • 자바
  • 스프링
  • 인프라
  • 카프카
  • 데이터베이스
  • 컨퍼런스
책
짧은 글
이력서
  • 꿈에도 배울 줄 몰랐던 C 언어

    • 1. C 언어를 배워보자
      • 1.1 새로운거 1 - switch 문과 if-else 문의 차이
      • 1.2. 새로운거 2 - 배열의 [] 는 연산자다.
    • 2. C vs Java: 이 책을 읽으며 특히 대비되는 지점
    • 3. 마무리하며

꿈에도 배울 줄 몰랐던 C 언어

2026년 1월 5일

회사에서 사용하기 위해 배우기 시작한 C 언어다. '강의 모음집'이지만 체계적인 구성과 600쪽 가까이 되는 PDF 를 가히 책이 아니라 할 수 없을 것이다.

1. C 언어를 배워보자

회사에서 C++ 을 사용할 일이 생겼다. 생겼다기보다는 내가 맡아서 한다고 했다. 그래서 같은 저자의 "씹어 먹는 C++ 언어"를 읽으려고 했는데 그 책에서는 C++ 문법 부분을 C 언어와 같다면서 거의 생략해버렸다. 그래서 하는 수 없이 C 도 함께 읽었다.

C 언어 자체는 대부분 언어의 기반이기 때문에 중요하다고 생각하고 있었지만 배우려는 생각은 없었다. 어셈블리어를 배울 필요가 없듯이 말이다. 하지만 이 책에서는 저자가 C 언어를 배우기를 강하게 권장하고 있다. 좋은 프로그래머가 되려면 컴퓨터 내부 원리를 알아야 하고, C가 그 이해를 가장 직접적으로 돕기때문이다. 그래서 책을 읽다 보면 C는 “요즘 유행하는 개발 스택”이라기보다, 컴퓨터와 친해지기 위한 언어, 즉 바닥 체력을 키우는 언어로 그려진다.

1.1 새로운거 1 - switch 문과 if-else 문의 차이

일단 if 문의 경우 각 경우 마다 값들을 비교 합니다. 위 경우 값을 3 번 비교하겠네요. 왜냐하면 if 가 1 번, else if 가 2 번이고 else 의 경우 값의 비교 없이 자동으로 처리되는 것이므로 총 3 번 비교하게 됩니다. 즉, if 문을 이용하면 각 case 의 경우 비교하게 되므로 최악의 경우 모든 case 에 대해 값을 비교하는 연산 (어셈블리어에서는 CMP 연산을 합니다.) 을 시행하게 됩니다.

그런데 switch 문은 사뭇 다릅니다. switch 의 경우 내부적으로 jump table 이라는 것을 생성합니다. 이 때, jump table 의 크기는 case 의 값들에 따라 달라지는데, 예를 들어서 어떤 switch 문의 경우 case 1: ∼ case 10: 까지 있었다고 합시다. 그렇다면 jump table 에는 값들이 0 부터 9 까지 들어가게 됩니다. 여기서 우리는 왜 case 값: 할 때, ’값’ 부분에 변수가 위치하면 안되는지 알게 됩니다. jump table 은 프로그램 초기에 작성 되기 때문에 이미 switch 문이 실행되기 전에 jump table 이 작성되게 됩니다. 따라서, ’값’ 부분에 변수가 들어가게 되면 jump table 에 무엇이 올지 알 수 없으므로 변수를 사용하면 안되는 것입니다. 이 값들은 무엇을 의미하냐면 각 case 별로 명령들이 위치한 곳의 주소를 가리키는데 예를 들어서 1 인 지점으로 점프하게 되면 "아이 시원해" 가 나오고 0 인 지점으로 점프하게 되면 "아이 맛있어" 라고 출력하라는 내용의 명령문들이 나옵니다. 이제, 변수의 값에 따라 변수가 3 이라면 jump table 의 3 번째 원소를 찾아서 그 값에 해당하는 곳으로 점프하게 됩니다.(실제로 switch 문이 처리되는 과정은 이보다 약간 더 복잡하지만 어셈블리어를 배우지 않은 현재 상황으로써는 최선이라 생각됩니다)

따라서, switch 문을 이용하면 case 에 따라 CMP 연산이 늘어나는 것이 아니라 jump table 의 크기만 커질 뿐 성능에 있어서는 전혀 영향을 받지 않게 됩니다. 결론적으로 이야기 하자면 switch 문이 효과적으로 처리되기 위해서는 case 의 ’값’ 들의 크기가 그다지 크지 않아야 하고, ’값’ 들이 순차적으로 정렬되어 있고, 그 ’값’ 끼리의 차이가 크지 않다면 최고로 효율적인 switch 문을 이용할 수 있게 됩니다.

1.2. 새로운거 2 - 배열의 [] 는 연산자다.

/* [] 연산자 */
#include <stdio.h>
int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    printf("a[3] : %d \n", arr[3]);
    printf("*(a+3) : %d \n", *(arr + 3));
    return 0;
}

성공적으로 컴파일 했다면 실행 결과

a[3] : 4

*(a+3) : 4

음... 이미 앞에서 다룬 내용을 모두 이해했더라면 위 정도쯤은 쉽게 이해할 수 있을 것입니다. 사실 컴퓨터는 C 에서 [] 라는 연산자가 쓰이면 자동적으로 위 처럼 형태로 바꾸어서 처리하게 됩니다. 즉, 우리가 arr[3] 이라 사용한 것은 사실 *(arr + 3) 으로 바뀌어서 처리가 된다는 뜻이지요. 그리고 arr 은 + 연산자와 사용되기 때문에 앞서 말했듯이 첫 번째 원소를 가리키는 포인터 로 변환 되어서 arr + 3 이 포인터 덧셈을 수행하게 됩니다. 그리고 이는 배열의 4 번째 원소를 가리키게 되겠지요.

2. C vs Java: 이 책을 읽으며 특히 대비되는 지점

책이 직접 Java는 이렇고 C는 저렇다를 길게 비교하진 않지만, 읽다 보면 차이가 자연스럽게 보이기는 한다.

  • 실행 모델: C는 보통 기계어로 컴파일돼 바로 실행되는 쪽에 가깝고, Java는 JVM 위에서 바이트코드가 실행되는 모델이라 한 겹 더 추상화가 더 있다. 책이 컴파일러를 강조하는 흐름 자체가 C의 관점을 보여준다.
  • 메모리 감각: C는 개발자가 메모리/주소 개념을 더 직접 다루는 언어고(포인터 등), Java는 GC와 런타임이 많은 부분을 대신 관리해주는 편이라 안전성과 생산성 vs 제어력의 결이 갈린다.
  • 언어 철학: Java는 객체지향과 표준 런타임 생태계를 강하게 전제하는 반면, C는 작지만 날것이라 컴퓨터 구조/OS/성능 감각이 키워진다. 책도 C 이후에 C++/Java 같은 OOP 언어로 확장하는 선택지를 언급하기도 한다.

3. 마무리하며

결국 이 책이 말하는 핵심은 C가 멋있어서가 아니라, C를 거치면 추상화 아래를 볼 수 있게 된다는 점이었다. Java로 개발할 때는 런타임과 프레임워크가 많은 걸 대신해주니 편하지만, 문제가 생겼을 때 왜를 끝까지 따라가려면 결국 컴파일, 메모리, 실행 모델 같은 바닥 지식이 필요해진다. C는 그 바닥을 가장 직접적으로 보여주는 언어였고, 그 과정이 당장은 느리고 불편해도 앞으로 어떤 언어를 쓰든 설계와 디버깅의 기준을 한 단계 내려준다.

이제는 C를 옛날 언어로 보기보다, 내가 쓰는 언어들을 더 깊게 이해하게 해주는 언어로 보게 됐다. C++을 제대로 다루기 위해서 시작했지만, 생각보다 더 큰 수확은 컴퓨터랑 대화하는 방식을 배웠다는 점이다. 그래서 당장 C로 무언가를 만들 계획이 없어도, 한 번쯤은 이 책처럼 차근차근 밑바닥을 밟아보는 걸 추천하고 싶다.