Offcanvas

개발자 / 애플리케이션

수십 년째 요지부동, 'C 언어'가 왕좌 지키는 이유

2022.09.30 Serdar Yegulalp  |  InfoWorld
‘C 언어’는 지난 1972년 개발돼 지금까지 전 세계적으로 널리 사용되고 있으며, 소프트웨어 시대의 핵심적인 기본 구성요소로 군림하고 있다. 하지만 지난 수십 년 동안 새로운 언어가 많이 등장했다. 그중에는 노골적으로 C 언어의 아성에 도전한 언어도 있었고, 인기를 끌면서 C 언어를 조금씩 갉아먹은 언어도 있었다. 여기서는 C 언어와 C++, 자바, C#, 러스트, 파이썬 그리고 ‘쌩신입’ 카본을 비교해 살펴봤다. 
 
ⓒGetty Images Bank

C vs. C++
C 언어의 가장 흔한 비교 대상은 C++다. 이름에서 알 수 있는 것처럼 C++는 C 언어의 확장판으로 개발됐다. C++의 구문 및 접근 방식은 C와 유사하지만 이는 네임 스페이스, 템플릿, 예외 처리, 자동 메모리 관리 등 C에서는 기본 제공하지 않는 매우 유용한 기능을 지원한다. 데이터베이스나 머신러닝 시스템 등 최상급 성능을 요하는 프로젝트는 C++의 이러한 기능을 사용해 작성되는 경우가 많다.

또한 C++는 C보다 훨씬 더 적극적인 확장 중이다. 곧 출시될 C++ 23은 모듈, 코루틴, 더 빠른 컴파일, 모듈화된 표준 라이브러리 등 많은 기능을 제공할 예정이다. 반면에 C 표준의 최신 버전(C2x)은 추가 기능이 거의 없으며, 하위 호환성 유지에 주안점을 두고 있다. 

문제는 C++의 모든 장점이 동시에 단점으로 작용하기도 한다는 것인데, 이 단점이 크다. C++의 기능을 많이 사용할수록 복잡성이 증가하며, 결과를 통제하기가 어려워진다. C++의 특정 부분만 제한적으로 사용하면 최악의 문제는 대부분 피할 수 있다. 이러한 복잡성을 원천적으로 차단하기도 한다. 예를 들면 리눅스 커널(Linux Kernel) 개발팀은 C++를 기피하며, 대부분의 리눅스는 여전히 C로 작성된다(현재 러스트를 향후 커널 추가를 위한 언어로 보고 있긴 하다). 

물론 C++가 고수준 기능을 풍부히 갖추고 있는 이유는 분명하다. 하지만 현재와 미래의 프로젝트 및 프로젝트팀에 미니멀리즘이 더 적합하다면 C를 사용하는 게 더 타당하다. 

C vs. 자바(Java)
자바는 개발된 지 수십 년이 지난 지금까지도 엔터프라이즈 소프트웨어 개발의 주축이며, 일반적인 개발의 필수 요소이기도 하다. 자바 구문은 C 및 C++에서 상당 부분을 차용했다. 하지만 C와 달리 자바는 네이티브 코드로 컴파일되지 않는다. 그 대신 자바의 JIT(just-in-time) 컴파일러가 자바 코드를 컴파일하여 타깃 환경에서 실행한다. JIT 엔진은 프로그램 동작을 기반으로 런타임 시 루틴을 최적화하여, 사전 컴파일된 C에서는 불가능한 많은 최적화 클래스를 허용한다. 적절한 조건 하에서 JIT로 컴파일된 자바 코드는 C의 성능에 근접하거나 심지어는 넘어서기도 한다.

또 자바 런타임은 메모리 관리를 자동화하는데, 몇몇 새로운 애플리케이션은 이를 우회하여 작동한다. 예를 들어 아파치 스파크는 메모리를 직접 할당 및 관리하고, JVM의 가비지 수십 시스템의 오버헤드를 피하기 위해 자바 런타임의 ‘언세이프’ 부분을 사용하여 인메모리 처리를 부분적으로 최적화한다. 

아울러 ‘한 번 작성하면 어디서든 실행’되는 자바의 특징 덕분에 자바 프로그램은 비교적 적은 조정으로 여러 타깃 아키텍처에서 실행될 수 있다. 이와 대조적으로 C는 매우 많은 아키텍처로 이식됐지만 예를 들어 특정 C 프로그램을 리눅스에서 윈도우로 가져와 (제대로) 실행하려면 이런저런 사용자 정의 작업이 필요하다.

이런 이식성과 강력한 성능의 조합 그리고 방대한 소프트웨어 라이브러리 및 프레임워크 생태계 덕분에 자바는 엔터프라이즈 애플리케이션 개발에서 가장 선호되는 언어이자 런타임이다. 자바가 C보다 떨어지는 부분은 기계와 근접한 위치에서 실행되거나 하드웨어를 직접 다루는 경우인데, 애초에 이 언어의 의도된 주력 분야가 아니긴 하다. 

C 코드는 기계어로 컴파일돼 프로세스에서 직접 실행된다. 자바는 JVM 인터프리터가 기계어로 변환하는 중간 코드인 바이트코드로 컴파일된다. 또 자바의 자동 메모리 관리는 대부분의 환경에서 유용하지만 제한된 메모리 리소스를 최적으로 사용해야 하는 프로그램에는 C가 더 적합하다.

C vs. C# 그리고 닷넷(.NET)
C#과 닷넷은 출시된 지 20년이 지난 지금도 여전히 엔터프라이즈 소프트웨어 개발 영역에서 주요 언어로 사용되고 있다. C#과 닷넷은 자바에 대한 마이크로소프트의 대응이었다고 평가된다(관리형 코드 컴파일러 시스템 및 범용 런타임). 또한 C와 자바가 비교되는 것만큼 C와 C#/닷넷과의 비교도 매우 많다. 

닷넷은 자바처럼(그리고 어느 정도 파이썬처럼) 다양한 플랫폼 간 이식성과 방대한 통합 소프트웨어 생태계를 제공한다. 닷넷에서 엔터프라이즈 개발이 얼마나 많이 이뤄지는지를 감안하면 상당한 이점이다. C# 혹은 다른 닷넷 언어로 프로그램을 개발하는 경우 닷넷 런타임용으로 작성된 수많은 도구 및 라이브러리를 활용할 수 있다. 

자바와 유사한 닷넷의 또 다른 장점은 JIT 최적화다. C#과 닷넷 프로그램은 C와 마찬가지로 사전 컴파일이 가능하지만 주로 닷넷 런타임에 의해 JIT로 컴파일되며, 런타임 정보를 통해 최적화된다. JIT 컴파일은 C에서는 할 수 없는, 닷넷 프로그램 실행을 위한 모든 종류의 즉각적인 최적화를 가능케 한다.  

C언어처럼(그리고 어느 정도는 자바처럼) C#과 닷넷은 메모리에 직접 액세스하기 위한 다양한 메커니즘을 제공한다. 힙, 스택, 비관리형 시스템 메모리는 모두 닷넷 API 및 객체를 통해 액세스할 수 있다. 또 개발자는 닷넷의 언세이프 모드(unsafe mode)를 사용해 성능을 높일 수 있다. 

물론 단점도 있다. 관리형 객체 및 언세이프 객체는 임의로 교환할 수 없으며, 두 객체 간 마샬링으로 성능이 저하될 수 있다. 따라서 닷넷 애플리케이션 성능 최대화는 곧 관리형 객체와 비관리형 객체 간의 움직임 최소화를 의미한다. 

관리형과 비관리형 메모리 간 불이익을 감수할 수 없다면 혹은 타깃 환경(예: 커널 공간)에 닷넷 런타임이 적합하지 않거나 전혀 사용할 수 없다면 C가 필요하다. 아울러 C는 C# 및 닷넷과 달리 기본적으로 직접적인 메모리 액세스를 해제한다.  

C vs. 고(Go)
구분자 역할을 하는 중괄호부터 문을 종결하는 세미콜론까지 고 구문에는 C에서 가져온 요소가 많다. C에 익숙한 개발자라면 큰 어려움 없이 고를 사용할 수 있다. 고의 설계 목표 중 하나는 ‘읽기 수월한 코드’였다. 개발자가 고 프로젝트에 쉽고 빠르게 적응하고, 짧은 시간 내에 코드베이스를 능숙하게 다룰 수 있도록 하는 데 주안점을 둔 것이다. C 코드베이스는 프로젝트 및 팀이 사용하는 온갖 매크로와 #ifdefs로 가득 차기 쉬운 만큼 파악하기 어려울 수 있다. 고의 구문 및 기본 코드 서식, 프로젝트 관리 도구는 이러한 C의 제도적 문제를 방지해준다.   

또한 고는 고루틴, 채널, 동시성 관리 및 구성요소 간 메시지 전달을 위한 언어 수준 도구 등의 부가적인 기능을 갖추고 있다. C에서 이런 작업을 하려면 수동으로 하거나 외부 라이브러리의 지원을 받아야 하지만 고에서는 기본으로 제공되기 때문에 이러한 요소가 필요한 소프트웨어를 쉽게 구축할 수 있다. 

고와 C의 차이점은 메모리 관리다. 고 객체는 기본적으로 자동 관리되고, 가비지로 수집된다. 대부분의 프로그래밍 작업에서는 상당히 편리할 수 있다. 하지만 결정적 메모리 처리를 필요로 하는 프로그램은 작성하기가 어렵다는 문제가 있다.

고에는 포인터(Pointer) 유형으로 임의의 메모리를 읽고 쓰는 등 유형 처리 안정성 중 일부를 우회하기 위한 언세이프 패키지가 포함돼 있다. 그러나 언세이프에는 ‘언세이프로 작성된 프로그램은 이식할 수 없고, 고 1(Go 1) 호환성 가이드라인으로 보호되지 않을 수 있다’라는 경고가 따른다. 

고는 명령줄 유틸리티 및 네트워크 서비스 등의 프로그램 구축에 적합하다. 이러한 프로그램은 세분화된 조작을 거의 필요로 하지 않기 때문이다. 하지만 저수준 디바이스 드라이버, 커널 공간 운영체제 구성요소, 메모리 레이아웃 및 관리에 정확한 제어를 요하는 작업이라면 C로 만드는 게 적합하다. 

C vs. 러스트(Rust)
어떤 면에서 러스트는 C 및 C++로 인한 메모리 관리의 어려움 그리고 이러한 언어의 많은 단점을 해결하는 방안이라고 할 수 있다. 러스트는 네이티브 기계 코드로 컴파일되기 때문에 성능에 있어서는 C와 동급으로 간주된다. 하지만 러스트의 가장 큰 매력 포인트는 기본적으로 제공되는 메모리 안전성이다.

러스트의 구문 및 컴파일 규칙은 개발자가 흔히 하는 메모리 관리 실수를 피하는 데 유용하다. 프로그램에 러스트 구문과 맞지 않는 메모리 관리 문제가 발생하면 컴파일 자체가 되지 않는다. 러스트를 처음 사용하는, 즉 C처럼 이러한 버그 발생 여지가 큰 언어를 사용했던 사람들은 러스트 학습의 첫 번째 단계로 컴파일러를 조심스럽게 다루는 방법을 배우게 된다. 러스트 지지자들은 이 단계가 장기적 보상, 즉 속도를 희생하지 않는 더 안전한 코드를 제공한다고 주장한다. 

아울러 러스트의 도구는 C보다 개선됐다. 고와 마찬가지로 러스트의 프로젝트 및 구성요소는 기본적으로 도구체인에 포함된다. 또 패키지 관리, 프로젝트 폴더 정리 등이 기본값으로 제공된다. C에서는 이러한 작업 처리 방식이 임시방편적이었을 뿐만 아니라, 각 프로젝트 및 팀이 각기 다른 방식으로 작업을 처리했다. 

하지만 러스트의 장점이 C 언어 개발자에게는 장점이 아닐 수 있다. 러스트의 컴파일 타임 안전 기능은 비활성화할 수 없기 때문에 가장 사소한 러스트 프로그램마저도 러스트의 메모리 안전 규정을 따라야 한다. C는 기본적으로 덜 안전할 순 있지만 훨씬 더 유연하고 관대하다. 

또 다른 단점은 러스트 언어의 크기다. 표준 라이브러리를 감안하더라도 C는 상대적으로 기능이 적다. 러스트는 기능이 상당히 많으며, 계속해서 확장 중이다. 러스트 역시 C++와 마찬가지로 기능이 많은 만큼 더욱 강력하지만 복잡성 역시 높다. 기능 면에서 C는 더 작은 언어지만 모델링하기 쉽기 때문에 러스트가 부담스러운 프로젝트에는 더 적합하다.  

C vs. 파이썬(Python)
요즘 소프트웨어 개발 관련 대화에서 파이썬은 단골 소재다. 파이썬은 ‘모든 용도로 사용하기에 두 번째로 좋은 언어’이며, 수천 개의 서드파티 라이브러리를 제공해 다방면에 유용한 언어 중 하나다.

파이썬이 강조하는 것이자 (이 언어가) C와 구분되는 점은 실행 속도보다 개발 속도를 우선시한다는 점이다. C로 작성하는 데 한 시간 정도 소요되는 프로그램을 파이썬에서는 몇 분 내로 만들 수 있다. 반면에 이 프로그램을 실행한다고 하면 C에서는 몇 초가 걸릴 수 있지만 파이썬에서는 몇 분이 걸릴 수 있다(일반적으로 파이썬 프로그램은 동일한 프로그램의 C 버전에 비해 한 자릿수만큼의 시간이 더 걸린다고 보면 된다). 하지만 최신 하드웨어에서 실행되는 많은 작업에서 파이썬은 충분히 빠르며, 바로 이 점이 그간 인기의 비결이었다.

또 한 가지 큰 차이점은 메모리 관리다. 파이썬 프로그램은 파이썬 런타임에 의해 메모리가 관리되기 때문에 개발자는 메모리 할당 및 해제에 하나하나 신경 쓰지 않아도 된다. 그러나 개발자가 편해진 만큼 런타임 성능은 저하된다. C 프로그램을 작성할 때는 메모리 관리에 세심하게 신경 써야 하지만 프로그램 속도는 순수한 기계의 속도 그대로다.

그렇지만 내부적으로 보면 파이썬과 C는 긴밀하게 연결돼 있다. 레퍼런스 파이썬 런타임이 C로 작성됐으며, 덕분에 파이썬 프로그램은 C 및 C++로 작성한 라이브러리를 래핑할 수 있다. 머신러닝 및 서드파티 라이브러리의 파이썬 생태계의 상당 부분은 C 코드를 근간으로 한다. 

따라서 ‘C vs. 파이썬’의 문제가 아니라 애플리케이션의 어떤 부분을 C로 혹은 파이썬으로 작성할 것인지에 관한 문제다. 개발 속도가 실행 속도보다 중요하거나, 성능 기준에 맞는 프로그램 부분 대다수가 독립적 구성 요소로 격리될 수 있다면 순수 파이썬 혹은 파이썬과 C 라이브러리의 결합이 C 단독보다 더 나은 선택이다. 그렇지 않다면 C가 적합하다. 

C vs. 카본(Carbon)
C와 C++의 잠재적인 경쟁자는 현재 개발 중인 새로운 언어 ‘카본’이다. 카본의 목표는 간단한 구문, 최신 도구 및 코드 구성 기술 그리고 C 및 C++ 개발자가 가지고 있는 고질적인 문제에 대한 해결책을 통해 C와 C++의 대안이 되는 것이다. 아울러 C++ 코드베이스와의 상호운용성을 제공할 계획이기 때문에 기존 코드를 점진적으로 마이그레이션할 수 있다. C와 C++는 최근에 개발된 언어에 비해 다소 오래된 도구와 프로세스를 제공하기 때문에 이는 환영할 만한 시도다.  

그렇다면 카본의 단점은 무엇일까? 프로덕션 환경에서 사용할 수 있는 준비가 전혀 되어 있지 않은 실험적인 프로젝트라는 점이다. 현시점에서는 작동하는 컴파일러조차 없는 온라인 코드 탐색기에 불과하다. 카본이 C나 C++의 실질적인 대안이 되기까지는 시간이 좀 걸릴 것으로 보인다. ciokr@idg.co.kr
 
추천 테크라이브러리

회사명:한국IDG 제호: ITWorld 주소 : 서울시 중구 세종대로 23, 4층 우)04512
등록번호 : 서울 아00743 등록일자 : 2009년 01월 19일

발행인 : 박형미 편집인 : 박재곤 청소년보호책임자 : 한정규
사업자 등록번호 : 214-87-22467 Tel : 02-558-6950

Copyright © 2022 International Data Group. All rights reserved.