C는 저수준 언어가 아니다: 당신의 컴퓨터는 빠른 PDP-11이 아니다

C Is Not a Low-Level Language (2018)

Meltdown과 Spectre 취약점의 근본 원인은 프로세서가 C 프로그래머들이 여전히 저수준 언어를 쓰고 있다고 믿게 하려고 복잡성을 추가했기 때문입니다. 실제로 C는 PDP-11 시절에는 저수준 언어였지만, 현대 프로세서는 추측 실행, 레지스터 리네이밍, 캐시 등으로 인해 C의 추상 머신과 전혀 다릅니다. C 코드를 빠르게 실행하려면 컴파일러가 수십만 줄의 복잡한 최적화를 수행해야 하며, 이는 종종 C의 의미론을 위반합니다. 이 기사는 C가 더 이상 하드웨어에 가깝지 않으며, 저수준 언어라는 환상이 보안 취약점과 성능 문제를 초래한다고 주장합니다.

프로세서 아키텍트들은 단지 빠른 프로세서를 만드는 것이 아니라, PDP-11과 동일한 추상 머신을 노출하는 빠른 프로세서를 만들기 위해 노력하고 있었습니다.
  1. weitendorf

    제 생각에는 이것은 정말 지나치게 세밀한 지적입니다. C가 저수준 언어인 이유는 기계어/어셈블리와 함께 작업하고 이런 것들을 매우 쉽게 할 수 있기 때문입니다 (LLM이 도와준 예시):

    int main() {

    __m512i vecA = _mm512_setr_epi32(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15);

    __m512i vecB = _mm512_setr_epi32(0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75);

    unsigned short mask = 0;

    __asm__ (

    "vp2intersectd %[B], %[A], %%k2"

    : "=@cck2" (mask)

    : [A] "v" (vecA), [B] "v" (vecB)

    : "k3"

    );

    printf("Intersection Mask: 0x%04X\n", mask);

    return 0;

    }

    이것은 "저수준" 프로그래머들이 고수준 언어의 이점을 누리면서 특정 하드웨어 명령어(vp2intersectd는 고도로 최적화된 검색 알고리즘 구현에서 사용되는 AVX-512 명령어)를 명시적으로 제어하기 위해 매우 자주 사용하는 것입니다.

    물론 컴파일러가 코드를 최적화하도록 암시적 동작에 의존한다면 더 이상 "저수준"이 아닙니다. 그러나 기계 수준 명령어로 빠르고 쉽게 내려가 명시적 구현 의미를 제공할 수 있고, 언어가 실제로 그렇게 하는 것을 상대적으로 간단하고 쉽게 만든다면, 그것은 확실히 저수준처럼 보입니다.

  2. bee_rider

    "저수준 언어"는 "VLSI"(초대규모 집적)와 같은 용어 중 하나로, 70년대에 정의되어서 학문적 정의가 대부분의 사람들이 기대하는 것과 동떨어져 있습니다.

    이것은 괜찮습니다. 전문 용어이고, 그런 용어는 즉시 명확할 필요가 없습니다.

    하지만 그런 이유로 이 글의 제목은 마음에 들지 않습니다. 정말 더 나은 제목은 "현대 x86 프로세서는 PDP-11이 아니다" 같은 것이었을 것입니다. 부제는 기본적으로 완벽합니다.

    편집: 또한 제 생각에는 이것에 대해 C를 비판하는 것은 공정하지 않습니다. 문제는 실제로 저수준성의 문제가 아닙니다. 추측 실행과 그 모든 것의 복잡성을 실제로 노출하는 언어는 꽤 고수준일 수 있습니다. 단지 선형 텍스트 편집기에서 읽기가 더 어려울 뿐입니다. 의존성 그래프를 그리는 것이 더 나을 것입니다.

  3. legobmw99

    저는 몇 년 동안 이 글의 팬이었습니다. 하지만 이 글이 종종 생각나게 하는 것은 우리의 슈퍼스칼라 현대 CPU를 위한 진정한 저수준 언어는 실제로 없다는 것입니다. 아는 사람 있나요?

  4. melodyogonna

    음, C는 중요할 때 제어권을 제공합니다. 더 현대적인 기능에 대해 덧붙인 것처럼 느껴지더라도 말이죠.

    저는 실제로 Mojo가 모든 컴퓨터가 PDP-11인 척하지 않도록 설계된 유일한 현대 언어라고 믿습니다. C가 너무 성공해서 많은 후속 언어들이 당연하게 C 방식을 따랐습니다.

    Mojo에서는 모든 것이 현대 컴퓨터의 복잡성을 염두에 두고 설계되었으며, 모든 단계에서 프로그래머는 결과를 완전히 제어할 수 있습니다. 무엇이 인라인될지, 무엇이 레지스터로 전달될지, 무엇이 언롤될지 등을 결정합니다. 이 언어는 훌륭한... 아니, 아마도 가장 이식성 좋은 SIMD 지원을 가지고 있습니다; 모든 정수는 SIMD 위에 구축되어 있고, 스칼라 정수는 길이가 1인 SIMD일 뿐입니다. 또한 강력한 컴파일 타임 프로그래밍 덕분에 무엇이 컴파일될지 완전히 제어할 수 있습니다. 이는 Zig와 비슷하지만 더 강력합니다(제 생각에는 더 많은 정보를 제공할 수 있기 때문입니다). C와 Rust가 인라인 어셈블리를 허용하는 반면, Mojo는 인라인 MLIR과 LLVM도 제공하여 더 나아갑니다. 따라서 상황이 필요하다면 컴파일러에게 특정 LLVM 내장 함수로 컴파일하도록 지시할 수 있습니다. 또한 이 언어는 단일 머신에서 실행되도록 컴파일한다고 가정하지 않습니다; 모든 현대 컴퓨터는 본질적으로 이기종이며 여러 프로그래밍 가능한 유닛을 포함할 수 있으므로, 컴파일 파이프라인은 코드의 일부를 한 대상으로, 다른 부분을 다른 대상으로 컴파일할 수 있도록 설계되었습니다... 하나의 컴파일 유닛으로 말이죠.

  5. glouwbug

    아마 그때는 아니지만, 기본적으로 우리는 이제 우리만의 가난한 사람의 템플릿 시스템을 가지고 있습니다:

    #define array(T, N) struct array##T##N { T value[N]; }

    void copy(array(int, 32)* x, array(int, 32)* y) {

    *x = *y;

    }

    int main() {

    array(int, 32) x;

    array(int, 32) y = { 1, 2, 3, 4 };

    copy(&x, &y);

    }

    (소문에 따르면) 람다와 defer가 곧 추가될 예정이라, C는 클래식 WoW의 길을 가고 있습니다.

    https://en.wikipedia.org/wiki/C29_(C_standard_revision)

이 날의 다른 글

2026-09-07