Redirected from page "C언어"

E,AHRSS

C(프로그래밍 언어)

last modified: 2015-12-07 13:16:47 Contributors

전산과 신입생은 CPU부터 시작해서 C를 활용하는 데까지 차곡차곡 기초를 닦아야 합니다. 저는 솔직히 너무나도 많은 컴퓨터 관련 교육과정들이 자바가 가장 좋은 초보자용 언어라고 선전하는 현실에 질려 버렸습니다. 흔히 자바는 쉽고, 따분한 문자열이나 malloc과 같은 골칫덩어리를 다루는 과정에서 혼란을 겪지 않으며, 아주 큰 프로그램을 모듈로 나눠서 만들 수 있는 근사한 객체지향 프로그래밍 기법을 배울 수 있다는 화려한 이유들이 따라 나옵니다. 하지만 여기에는 교육적인 재앙이 있습니다. 졸업생들은 하향 평준화돼 러시아 페인트공 알고리즘[1]을 여기저기에 만들어내며, 심지어 자신의 잘못을 인식조차 못할 겁니다. 펄 스크립트에서 이런 사실을 결코 볼 수 없을지라도, (물론 어렵지만) 기본적으로 문자열이 무엇인지 아주 깊은 단계에서 이해하지 못하기 때문입니다. 다른 이들이 뭔가를 잘하도록 가르치길 원한다면, 기초부터 시작해야 합니다. 이는 마치 영화 '가라테 키드'와 비슷합니다. 마루바닥을 쓸고 닦고 쓸고 닦고, 이렇게 3주만 하면, 자연스럽게 목표물을 향해 발이 쭉쭉 뻗어나갑니다.3주간 마루바닥을 쓸으면 러시아식 페인트질을 안 하게 되는건가!
-- 조엘 온 소프트웨어 (조엘 스폴스키)
어이쿠 그 싫어하시는 SICP[2]스러운 발언을 하고 자빠졌네

Contents

1. 개요
2. 역사
3. 설명
3.1. 단점
4. 포인터
4.1. 중괄호 스타일
4.2. 장점
4.2.1. 과거
4.2.2. 현재
5. 점유율과 플랫폼별 지원상황
6. 다른 언어에 미친 영향
7. C 언어용 컴파일러/개발 도구들

1. 개요

1972년에 벨 연구소(Bell Labs)의 데니스 리치(Dennis MacAlistair Ritchie, 1941.9.9~2011.10.12)가 만든 프로그래밍 언어. 대표적인 프로그래밍 언어로 특히 대한민국에서는 프로그래머의 기본이 되는 언어. 보통 C 언어라고 한다.

2. 역사

케임브리지 대학교 에서 시작된 CPL 이라는 언어에서 BCPL(Basic CPL) 이 탄생하였고, BCPL 이 미쿡으로 물건너와 켄 톰슨이 B 라는 언어를 만든 후에, 같은 벨 연구소의 데니스 리치가 최종적으로 'C'라는 이름으로 언어를 만들었다. 참고로, CPL 의 'C' 는 케임브리지 대학의 C 를 의미했다가 후에 임페리얼 칼리지 런던과 조인트 프로젝트가 된 이후에는 'Combined' 를 의미하게 되는데, Stroustrup 의 회고에 의하면 저건 윗분들의 생각이고, 자신들에게 있어서 'C' 는 언제나 CPL 의 언어 디자이너였던 Christopher Strachey 였다고 한다. BCPL 을 거쳐 B 가 된것은 '벨' 연구소의 B를 딴 것. 그리고, 후에 C 가 되면서 한때는 프로그래머 유머로 C 다음 언어가 과연 D일지 P일지 묻는 이야기가 있었지만 C++같은 것도 나왔고, Ansi C, C99, C0xC11[3] 등등등[4]으로 가지를 뻗으며 진화중인 현재의 C언어에게는 이미 과거의 이야기가 되어버렸다. 사실 D라는 프로그래밍 언어도 있기는 있다. 벨 연구소가 아닌 디지털 마르스(Digital Mars)에서 만든 것이기는 하지만. ABA Games 의 게임들 대부분도 이것으로 만든 것이다.

참고로 ++은 그 변수를 1증가시켜 대입하는 연산자이다. 다시말해 C++에서 ++은 C를 1 증가시켜 대입했다는 말. 적절한 작명이다. C#에서 #은 ++++이다(++이 위 아래로 두개)... 잠깐, (c++)++은 문법에 맞지 않을 텐데? 라는 말도 있으나 실은 C♯, 그러니깐 음악에서 유래했다. 어쩐지 C와 심하게 다르다 했다면 착각이 아니다!!

3. 설명

C 의 정신(...)은 C99 Rationale 에서 다음과 같이 묘사하고 있다.

  • Trust the programmer
  • Don't prevent the programmer from doing what needs to be done
  • Keep the language small and simple
  • Provide only one way to do an operation
  • Make it fast, even if it is not guaranteed to be portable

첫줄의 '프로그래머를 믿어라' 부분이 오늘날 다른 언어들과 가장 큰 차이를 불러오는 것이다. 오늘날 다른 고생산성 언어들이 프로그래머를 못믿고 퍼포먼스 희생을 감수하고서라도 문제가 생길만한 부분들을 컴파일러에서 자동으로 처리해준다면, C는 "믿을테니까 알아서 해라." 한마디로 끝낸다고 보면 된다. 그래서 어딘가에서는 누군가가 비명을 지르고 있다(...)

C 언어 이전에도 고수준 언어들은 많이 존재했지만, 대부분 특정 어플리케이션 영역을 타겟으로 하거나, 컴퓨터 과학 이론을 입증하기 위해 만들어진 실험실 언어들이었다. 어플리케이션 영역이 아닌 운영체제를 어셈블리어가 아닌 언어로 작성한다는것은 당시엔 일종의 금기에 가까웠고[5], C 언어와 유닉스는 소수의 예외를 제외하고 대부분을 C 언어로 작성하고서도 우려와는 달리 단점보다 장점이 훨씬 많다는것을 보이면서 이 금기에 정면으로 도전해서 승리하였다고 볼 수 있다. 그리고 지금은 운영체제는 C 언어가 아니면 안된다는 새로운 금기가 생겼다. (...) 토발즈같은 커널 메인테이너들이 C++을 싫어하는 것도 한몫하는 듯.

세계적으로 엄청나게 많이 쓰이는 프로그래밍 언어로 대한민국에서는 특히 비중이 높다. 어셈블리 코드를 코드 안에 집어넣어서 구동 속도 면에서 이점을 얻을 수도 있으며(그러나 매우 어렵고 호환성은 안드로메다로...) 기본적으로는 기존의 언어들물론 어디까지나 C가 탄생하던 6-70년대 이야기다.에 비해 매우 이해가 가기 쉬운 문법을 사용하여 초보자가 쉽게 접근할 수 있도록 제작되었다. 참고로 C가 개발된 시기는 70년대인데, C 개발 전에 주로 쓰이던 코볼 내지 포트란이 얼마나 불친절한 언어인지는 더 이상의 자세한 설명은 생략한다. 요즘 프로그래밍에 입문하는 사람들은 상상도 못하겠지만 코볼과 포트란은 소스 코딩할 때 칸까지 맞추어야 했다. 파이썬?제일 왼쪽 몇 칸은 주석, 그 다음 몇 칸은 정의... 이런 식으로.이 언어들은 천공카드가 쓰이던 시절 만들어져서 그렇다. 그리고 사실 코볼의 경우 원래는 프로그램 코드가 업무 서류로도 사용이 가능하도록(!) 설계가 돼있어서 그렇다. 주석이 코드고 코드가 주석일경우의 아주 나쁜 사례. 2000년대에 애자일 프로그래밍 정신중 하나로 부활했다 카더라.[6]

다른 언어들의 경우 여러 교재들이 서로 경쟁하는 추세이지만, 유독 C 의 경우는 창시자인 데니스 리치와 브라이언 커니건이 쓴 The C Programming language 2nd Edition 이 독보적인 위치를 점하고 있다. 이 두사람의 이니셜을 따서 보통 K&R 이라 칭한다.[7] 이 책이 나온지 매우 오래 되긴 했지만, C 라는 언어가 별로 변화가 없는 언어인데다가 C99, C11 등 ISO에서 계속 업데이트를 했음에도 불구하고 캐무시하는 프로그래머들의 성향[8] 때문에 ANSI C 가 현재 사실상 표준인 상태이다.[9] 또한, 분량은 전부 다합쳐도 300페이지도 안된다. 그것도 Appendix 부분을 빼면 순수 튜토리얼은 200페이지도 안되며, 언어 자체뿐 아니라 프로그래밍에 대한 여러가지 깨알같은 조언까지 다 포함이 되어있다. 보통, 일반적인 프로그래밍 언어 교재가 작아도 500 페이지를 가볍게 넘어가고, C++의 창시자인 Bjarne Stroustrup 이 K&R 과 비슷한 네이밍으로 쓴 The C++ Programming language 의 경우 1000페이지에 육박하는것[10]에 비하면 엄청나게 짧은 분량이라 할 수 있다. 그러나, 분량이 많은 교재들은 그만큼 친절하고 자세한 설명을 동반하여 비교적 술술 읽히는것에 반해, K&R 은 짧은만큼 매 문장 하나하나[11]의 중요도가 높기 때문에 프로그래밍 초심자에게 추천할만한 책은 아니라는 주장도 있다.그런데, The C++ Programming Language는 난이도도 TCPL 보다 더 높다. 사실, K&R이 바이블 취급을 받는 이유는 단순히 역사적이고 C 언어 창시자가 쓴 책이기 때문만은 아니다. C 언어가 겉으로는 심플해보이지만 워낙 숨은 함정이 많은 언어라, 저런 부분들을 제대로 다 짚고 넘어가야 하는데, K&R 이외에 제대로 완전하게 짚어주는 교재가 거의 없다. 보통의 고수준 언어들처럼 접근해서 직관적으로 '이렇게 하면 된다.' 식으로 설명을 하는 교재들이 많은데, 사실 온갖 정의되지 않은 행동(Undefined Behaviour)과 implementation-specific details, 하드웨어에 의존적인(hardware dependent) 함정들이 곳곳에 숨어있는 C 언어는 '이렇게 하면 된다.' 보다 '이렇게 하면 안된다.'를 중점적으로 설명해야 하는 언어이다. 특히나 UI 나 퍼포먼스 중심으로 돌아가는 어플리케이션 영역이 메인인 언어들과는 달리, OS 와 딱 붙어서 보안이나 안정성 및 호환성이 중시되는 시스템 프로그래밍 영역이 메인인 언어라 어느정도 깐깐하게 접근하는게 맞는 언어이다.[12] C 언어를 C++이나 Objective-C를 익히기 전의 워밍업정도로 취급하는 사람들에게는 저런식으로 설렁설렁 쉽게 써진 C 교재들도 좋은 평가를 듣는 경우도 많지만, 본격적으로 C 프로그래밍을 하려는 사람들 사이에서는 해외 기준으로 K&R과 C Programming A Modern Approach 두개정도만 제대로 된 교재 취급을 받는다. 국내교재나 대학의 경우, 닥치고 윈도우 기준으로 설명하는 경우가 많은데, 비주얼 스튜디오 컴파일러는 ANSI C를 기반으로 상당히 많은 비표준 확장을 제공하고 있다. gcc 역시 비표준 확장을 많이 제공하지만, 이후의 표준인 C99, C11 에서 그런 비표준 확장 상당부분이 표준화되었고 gcc 는 C99도 지원하므로 상황이 나은편이다. 웬만하면 유닉스에서 표준으로 먼저 배우고 MS 나 gcc 등의 비표준 기능은 차후에 문서보고 따로 익히거나, 꼭 MSVC로 배우고싶다면 표준과 비표준, 나아가서 가능하면 C89/C99 의 기능을 구분해서 설명하는 교재로 배우는게 나중을 위해서 훨씬 나은 선택이다.근데 어차피 C 는 MS 월드에서 찬밥이다. C 언어는 유닉스를 만들기 위한 언어로 시작했기 때문에 유닉스 표준인 POSIX 와도 관련이 깊고, 결국 제대로 표준으로 공부하려면 어찌됐건 유닉스 환경이 훨씬 편리하다. 그냥 자바 배워 자바

대한민국에선 많은 곳이 C 혹은 C++로 공부를 시작하며 나머지는 자바, C#, 비주얼 베이직, 어도비 플래시(액션스크립트) 등이 차지하고 있다. 즉 독점에 가까운 위치를 점유하고 있다. 이는 각 대학교 혹은 학원들의 커리큘럼 탓이 가장 크다고 볼 수 있는데, 이 때문에 아직도 '자바 먼저' vs 'C 먼저'의 떡밥은 개발자들 사이에서의 좋은 키배거리가 되고 있다. 그러나 후술할 듯 C가 미친 영향은 자바를 포함해서 매우 광범위한지라 어떻게 해도 결국 C가 1라운드 보스 맨 앞에 선다(……). 사실,대한민국에서는 이게 프로그래밍 언어의 기초쯤 되는 취급을 받고 있다. 하지만 C언어 자체의 난이도는 위에서 봤듯이 무시할게 못된다.

C언어 자체는 지원되는 기능이 적기에 배우기가 크게 어렵지는 않다. 다른 프로그래밍 언어를 배운 경험자라면 대강의 기본적인 문법 정도는 늦어도 며칠, 빠르면 심지어 수시간 내에 습득이 가능할정도. 특히나, OOP 등 생각과 경험을 요구하는 고수준 기능들이 명시적으로 제공되지 않기에 단순 문법정도가 사실 언어가 제공하는 전부다. C언어 커리큘럼의 절반을 함수 사용법에 의존할 정도.(……) 게다가 그 함수도 150 여개밖에 안된다. 다른 고생산성 언어들, 예를들어 PHP 만 봐도 함수가 수천개가 넘어간다.

하지만 기능이 적다고 결코 쉬운 건 아니다. 초반의 포인터 장벽만 넘는다면 문법 자체를 마스터하고 간단한 커맨드라인 프로그래밍을 할 수 있는 수준까지는 엄청 쉽지만, 프로그래밍이란 게 기능이 적다고 그 적은 기능만 쓰는건 절대로 아니다. 없으면 결국 직접 구현해서 쓰게 되는데, 거의 30년간 프로그래밍 언어계에서 오늘날 영어와 같은 위치를 차지하고 있던 덕분에 그런 기능의 구현이나 최적화에 관한 많은 트릭들이 존재하고 이것을 얼마나 많이 알고있는가가 사실 C 언어의 핵심이다. K&R이 좋은 교재인건 맞지만 오늘날 K&R을 교재로 추천하기가 마냥 좋지만은 않은 이유중 하나도 너무 오래되서 초창기 C 언어의 유행이나 트릭정도만을 담고있고, 그 이후의 여러가지 트릭이나 패러다임의 변화등을 반영하지 못하고 있기 때문이다.[13] 또한, 오늘날 고수준 언어들이 다수의 프로그래머가 함께 개발하는것을 염두에 두고 팀에 누가 될만한 위험하거나 생산성에 저해되는 부분들을 언어차원에서 강제로 제외시키는 경향이 있다면, C 언어는 저것들에 대해 완전히 개방된 언어에 속한다.[14] 상황이 이렇다보니 같은 프로그램이라도 프로그래머의 지식수준과 능력에 따라 퀄리티 차이가 그야말로 극과 극으로 벌어지는 언어이다.

또한, 그 실력을 충분히 발휘하려면 주로 쓰이는 분야에서 사용하게 되는 기술을 익혀야 하는데, 그 분야라는 것이 하필 기계제어. 제대로 사용하려면 프로그래머들이 보통 싫어하는 지저분한하드웨어와 어셈블리어에도 결국 손을 대야 한다.

C는 작지만 어셈블리어 다음으로 기계레벨까지 접근 가능하고, 충분히 강력한 언어이기 때문에 C의 힘을 제대로 발휘하려면 어셈블리어 수준으로 프로그래밍해야 하고 하드웨어의 기능을 꿰어차고 있어야 한다. 오죽하면 C가 '시스템 독립적인 어셈블리'(System Independent Assembly)라 불릴 정도. 애초에 C 자체가 운영체제를 만들기 위해 고안된 언어이니만큼 그럴 수밖에 없었다.

일반적인 프로그래밍도 역시 가능하지만, 그런 용도로는 더 적합한 언어들이 널려있다. 현재 대한민국에서는 양산형 자바 유저들(..)이 C언어 우습게 봤다가 데꿀멍하는 사태가 자주 있다.

즉, 초심자가 C언어를 배우는것까지는 물론 문제가 없지만 배우고 나서 뭔가 제대로 할만한게 거의 없다고 보면 된다. 그리고, 바로 그렇기때문에 프로그래밍 입문용 언어의 자리도 해외기준으로는 자바나 파이썬등으로 거의 대체되었다. 아두이노가 있지 않나?

그래도 정 배우고 싶은 사람은 이곳을 참조해보자. JoinC 이것을 쉽게 배울수 있는 보드게임도 있다.

3.1. 단점

닥치고 성능이라는 대명제에 충실해서 작게는 변수 초기화, 배열 범위 점검, 허상포인터(Null Pointer) 문제에서부터 크게는 쓰레기 수집(Garbege Collection; GC), 예외처리 같은 경우까지 조금이라도 하드웨어에 오버헤드가 걸릴것같은 기능은 다 무시한(그래서 프로그래머가 그런거까지 다 신경써야되는), 저급프로그래머 입장에서는 악몽같은 언어다. 이 모양인 이유는 사실 C가 처음 나왔을 때는 그런 기능들에 신경쓸 여유도 없는 데다가[15] 그 당시에는 프로그래머라면 모름지기 저걸 알아서 관리해가며 쓰는게 기본이었기 때문. 그러니까 현재 기준으로 봤을 때는 1970년대에 만든 물건이라 현대에 만든 개념을 전혀 신경쓰지 않았으니. 신경쓸 수가 없잖은가? 어쩌면 당연한 것.

덕분에 어셈블리어에 비해 호환성이 좋다고는 하지만, 하드웨어마다 달라지는 부분들을 언어 내에서 컨트롤해서 일관성을 유지하는 게 아니라, 성능을 위해서 전혀 후처리를 하지 않고 그대로 프로그램에 반영해버리기 때문에 사실 C언어의 호환성도 미신이라는 사람들이 많다. 그나마, C99에서는 컴퓨터 성능이 좀 올라간걸 반영해서 여러가지 엣지케이스에 대해 어느정도 통일성을 만들려고 한 노력이 엿보이긴 한다.

C++에서는 저보다 조금 나아지긴 했지만 포인터를 그대로 유지하면서 여러가지 상위개념을 얹었기때문에 말 그대로 조금이다. 특히나 저 포인터에 더해서 여러가지 상위개념들의 컨셉까지 익혀야 하고, 그것들과 포인터의 화려한 향연까지 존재하기때문에 습득하기도 엄청나게 어려운 언어가 되었다. 저수준부터 고수준까지 다되긴 하지만, 일단 발을 들여놓으면 그야말로 평생 공부해야 하는 평생언어가 되었다. C++에 들어서서 STL이 개발되어 그보다 조금 고급 개념을 제공하기는 한다. 그래도 위에 나온 것들 신경 덜 쓰고 싶다면 현재 쓰는 개념을 꽤 많이 탑재한 자바가 낫다.

추가로 아래와 같은 점들 때문에 종종 C가 까이곤 한다.
  • 느슨한 타입 검사. 초창기의 K&R C에 비해 ANSI C부터 타입검사가 비교적 양호해졌지만 아직도 서로 다른 종류의 포인터끼리의 대입조차 가능하다. 사실 느슨한 타입 검사 자체가 나쁜 건 아니고 최신 언어들은 느슨한 타입 검사를 채용하는 언어가 많은데, 문제는 C는 강타입 언어라 느슨한 타입 검사를 통과한 타입 미스매치가 실행시에 치명적인 문제를 일으킬 수 있다는 거.
  • 배열의 첫번째 항이 0번이다. 일반적으로 시작은 1번이라고 생각하기 때문에 C를 처음 배울 때 혼란을 겪는 사람들이 제법 있다. 사실 선언한 배열의 배열명은 포인터 상수이며, arr[3]이라는 것은 arr라는 포인터 상수 위치로부터 3 만큼 떨어진 요소를 뜻한다.[16] 이렇게 생각하면 좀 더 이해하기 쉬울 것이다. 이러한 이유는 배열도 기본적으로 포인터로 관리가 되는데, 포인터가 가리키는 메모리 영역을 억세스 할때 포인터 연산을 사용하기 때문. 그런데 사실, 이것도 따지고보면 하드웨어때문이다. 1부터 시작하게 만들면 배열에 접근시 항상 1 을 빼줘야돼서 오버헤드가 생기기때문.
  • 배열 안에 접근할 때, 인덱스가 배열 범위를 벗어나도 이를 체크하지 않는다. 이는 C언어에서 배열을 경계가 정해진 추상적인 자료구조로 취급하는 게 아닌, 연속적인 메모리 뭉치의 첫부분을 가리키는 포인터로 다루기 때문에 일어난다. 때문에 이런 구조체 핵같은 변태같은 짓도 가능한데, 예로 구조체 struct _EE_PACKET 에서 앞부분의 데이터는 int cnt; int checksum; int magic; 3개의 int형 변수를 가지며 당연히 이들의 자료형 크기는 불변이다. 하지만 이 구조체 바로 뒷부분에 다수의 struct _EE_EE의 구조체 데이터가 붙어 오게 되며 몇 개가 있는지는 _EE_PACKET 구조체 내부의 cnt에 의해 정해진다. (즉, 가변이다.) 이러한 경우 뒤의 _EE_EE 구조체 데이터에 접근하기 위해서는 struct _EE_EE *EE = (struct _EE_EE *)(((struct _EE_PACKET *)packet_ptr) + 1); 와 같이 할 수도 있지만, _EE_PACKET의 제일 뒷부분에 struct _EE_EE EE[0]; 을 넣어 주고 struct _EE_EE *EE = &packet_ptr->EE[0]; 처럼 할 수도 있다. zero-sized array이나 구조체 내의 변수선언부분의 제일 뒤라면 선언해도 문제가 되지는 않는다. 이는 사실 struct hack 이라는 유명한 트릭으로, 왠만한(제대로 된) C 교재에서도 대부분 다루고 있다. 참고로, ANSI C 에서는 zero-sized array 를 보장하지 않았기때문에 과거에는 주로 더미값 [1] 을 사용했는데, 이 트릭이 워낙 자주 쓰이다보니 gcc 등 C 컴파일러들은 저 트릭을 위해 자체적으로 zero-sized array 를 따로 허용을 하였고, 결국 C99 에 와서 flexible array member 라는 이름으로 표준화가 되었다.(C99 에서는 struct 마지막 어레이 멤버에 [0] 대신에 그냥 [] 로 써주면 된다.) ]. 이렇게 배열 범위를 체크하지 않는다는 점은 심각한 보안 구멍을 만들어낸다. 일명 buffer overflow 취약점이라고도 하는데 배열 체크를 하지 않는 C언어 때문에 생기는 보안 상의 만악의 근원. 물론 프로그래머가 꼼꼼히 체크하면 되긴 하는데 여러분도 알다시피 프로그래머는 항상 실수한다(..) 따라서 언어 자체에 내재된 취약점이라 볼 수 있다. [17][18]
  • 문자열 타입이 없어서 문자형 배열을 사용한다. 이것 때문에 널 문자라고 해서 문자열의 끝을 알리는 문자를 쓴다. 널 문자 때문에 일어나는 오류도 적지 않다.문자열을 출렸했는데 뒤에 왠지모를 한자가 딸려나온다거나.. 긄꿻얋儆儆儆儆儆儆儆儆 라인피드와 캐리지리턴까지 섞이면 이때는 대략 정신이 멍해진다 또한, 포인터와 맞물리면 또한번 초심자들에게 문제가 되는데, 문자열 리터럴 자체가 '값'이라기보다는 해당 문자열의 '주소'를 가리키기때문에 문자열 포인터를 사용하는 경우, 그것이 포인터여도 문자열을 가져올때 dereferencing을 하면 안된다.[19] ANSI C 이전의 구버전 K&R C 에서는 void* 가 없었고, char* 가 그 역할을 맡았었다.[20]
  • &&와 ||, &와 | 들이 헷갈린다. 앞의 두 개는 논리값에 대해 AND와 OR연산을 하고, 뒤의 두 개는 비트 단위의 AND와 OR 연산을 한다. 게다가, false는 0 이고, true는 0 이 아닌 모든 integer가 되기때문에 논리연산자를 사용해야 할곳에 실수로 비트연산자를 사용했을때 심지어 전혀 문제없이 컴파일이 되어 버그잡는데 골머리를 썩히는 경우도 많다.(아니, 이런경우 버그가 있는지 인식하기조차 힘들다.) 그러나 이런 표기법이 C가 나온 이래 de facto 표현이 되어서 Java, javascript등 수많은 언어들에 적용되었기 때문에 한번 프로그래밍에 익숙해지면 문제없다(..)

  • 위에서 밝혔지만 =가 등호기호가 아닌 대입연산자이기 때문에 수학을 배운 사람들에게 혼란을 가져온다. 정작 대입연산을 해야할 시점이 아닌 한참 앞에서 =를 적어 놓고서는 의도한 대로 동작하지 않는 것에 의구심을 가지는 초보자들도....특히나 실수로 == 를 쓸곳에 = 를 하나만 찍는 오타를 범했을경우, integer 값이 리턴되는 경우에는 역시 문제없이 컴파일되고 직접 돌려서 해당 기능이 오작동을 하기 전까지 버그를 알아챌수조차 없게된다. 이때문에 == 사용시 lvalue 에 일부러 상수항을 사용하는 프로그래머들도 있다.[21][22]
  • int 형 자료형과 double 형 자료형만 존재하는 느낌이 들 수 있다. 실제로, 모든 리터럴은 뒤에 f 등의 타입을 붙여주지 않으면 그냥 int 아니면 double 이다. char건 true/false 값이건 short 건 그냥 다 int로 간주한다. 그리고, 타입변환이 필요할 때마다 정수 진급(integral promotion, C99에선 integer promotion)이라 해서, char, short 등의 타입은 일단 먼저 int로 바꾸고 나서 변환을 시작한다. bool 타입은 존재하지도 않으며[23], 0은 false이고, 나머지 다른 것들은 전부 true로 처리한다.[24] 때문에 임의의 char 값이 숫자인지 알아보는 isdigit 함수는 숫자가 아니면 0을 리턴하지만, 숫자일 경우 보통 1을 리턴하기니 하지만, 0이 아닌 그냥 어떤 수를 리턴하는 컴파일러도 있다. 매뉴얼페이지에는 보통 non-zero라고 되어있다. (...) 비슷하게 논리적 부정 연산을 의미하는 !의 경우는 0일 경우 1로, 0이 아닌 다른 모든 값은 0으로 바꾼다. char 타입은 아예 int형 타입과 거의 자유자재로 호환이 되며[25], 'A' 같이 분명히 char 타입으로 보이는것들도 실상은 char 타입이 아니라, int 타입이다. (..) 문자열은 그냥 char 형 배열로 쓴다. 문자열 값의 끝에 붙는 널문자 '\0' 역시 int 값으로 그냥 0 이다.[26] 덕분에 언어 자체의 syntax/semantics를 넘어서 저런것들로 만들어지는 여러가지 꼼수와 내부적으로 처리하는 방식, 머신따라 달라지는 부분까지 염두에 두어야 한다.
  • 배열과 포인터의 차이가 비직관적이다. 사실 이 부분이 C 언어를 배우는데 가장 커다란 난관이 되는 부분이다. 배열과 포인터는 비슷하다고 보기에는 차이가 너무 크고, 다르다고 보기에는 비슷한 부분이 너무 많다. 덕분에 교재마다 접근방법이 달라지는데, 어떤 교재에서는 '비슷하다'고 전제한 뒤 차이점을 설명하는식이고, 어떤 교재에서는 '다르다'고 전제한 뒤 공통점을 설명하는식이다. 어느쪽으로 접근하더라도 함정과 예외가 상당히 많아지기 때문에, 둘의 차이를 충분히 구분할만한 상황적 경험이 적을수밖에 없는 초심자들에게 결국은 이해보다 암기로 흘러가고 어렵다고 느끼는 경우가 많다. 실제로, 일차원 배열과 레벨 1 포인터(*p)는 의 경우에는 차이점보다 공통점이 더 많지만, 다차원배열과 고레벨(multi-depth) 포인터는 차이점이 더 많은편이다. 그리고, 함수를 통해 넘겨주게 되는 경우에는 배열도 포인터로서 넘어가기때문에 동일해진다. 또한, 타입체킹이 있긴 있지만 엄밀한 편은 아니어서, 타입을 무시하고 주소값만 연상하면서 접근할 경우, 타입체킹에 걸려서 에러가 나는 경우도 빈번하고, 그렇다고 엄밀하게 타입 위주로만 접근할 경우, 매우 유용할 수 있는 많은 트릭을 포기해야 한다. 즉, 초심자 입장에서는 일단 암기하고 그냥 경험적으로 익숙해지는게 최선.

C 언어에는 저런 함정들이 매우 많이 도사리고 있으며, C 언어를 배운다는것은 사실 '어떻게 프로그램을 만들것인가' 를 배우는게 아니라, '어떻게 저런 함정을 피해갈것인가' 를 배우는거라는 사람도 있다.

뭐 다 C로 과제 몇번하면서 두뇌개조 당하고 나면 자연스럽게 되는 것들이다. 정말로. 위에 나온 대부분의 단점들은 한마디로 인간이 자연스럽게 쓰기 힘들다는 것인데, C의 컨셉이 그런 것이니 당연한 것이다. 인간인 프로그래머와의 친화가 우선이 아니라 컴퓨터와의 친화가 우선인 언어인 것이다. C와 컴퓨터 및 운영체제의 이해가 깊어지다 보면 왜 이렇게 쓰기 불편하게 만들어진게 사실 당연한 선택이었는지 이해가 간다.[27]

그래서 조금 불편하지만 반대로 이 때문에 저레벨상에서 더 유연한 프로그래밍을 할 수 있다.오히려 다른 언어는 변수 타입이나 참조 등에 제약이 많아 저레벨 프로그래밍을 할 때는 C언어보다 더 불편한 면이 있다. 예를 들어서 블록 암호화같이 비트/바이트단위로 바이너리를 자유자재로 조작해야하는 코드는 고수준 언어로 짜기 불편하다. 익숙해지면 구조체 같은 사용자 정의 데이터 타입을 이리저리 캐스팅해서 포인터 연산을 활용해 전혀 엉뚱한 데이터로 변환해서 쓰는것도 가능하다.[28]

사실, 초창기 C 언어는 비교적 사용하기 편리한 고수준 언어로 분류되었고 그렇기때문에 큰 인기를 끌었지만, 오늘날 C 언어는 오히려 불편한 언어에 속한다. 그럼에도 불구하고 많이 사용되는 이유중 하나는 투명성이다. 고수준 언어들의 경우, 하드웨어로부터 거의 완전히 추상화를 시킨 경우가 많기때문에 프로그램 로직에만 신경쓰면 된다는 장점이 있지만, 그게 정확히 컴퓨터에서 어떤식으로 돌아가는지를 예측하기는 그 추상화 수준만큼 힘들어지게 된다. 반면, C 언어는 기능 자체가 적고 하드웨어에 맞춤형태로 최소한도의 추상화만 시킨 수준이기때문에, 어셈블리어와의 호환성도 좋고 코딩과 동시에 실제 어떤식으로 하드웨어가 움직일지 예상이 비교적 쉽다. C++만 봐도 C가 할 수 있는 저수준 작업을 다 가능하다고 하지만, 가능하다뿐이고 C++에서 제공하는 고수준 기능들을 사용하게 되면 그게 실제 어떻게 작동하는지는 코딩하면서 머리로 그리기가 아주 힘들어진다.실제로 여타 고수준 언어들처럼 C++ 에서도 그런 고수준 기능들의 디테일은 신경을 끄라고 말한다.

그렇기때문에 C 언어로 코딩을 한다는것은 곧 저런 장점을 살리고싶다는것이고, 그러려면 결국 하드웨어에 대한 지식도 필요하며, C 언어 자체에 대해서도 아주 디테일한 수준까지 알고 있어야 한다. 이런 측면때문에 복잡한 기능들을 많이 제공하는 고수준 언어들에 비해 쉽다고 보긴 힘들다.

4. 포인터

C에서 지원하는 유도형[29]식의 자료형 중 하나.

C를 배우는 사람들은 포인터에서 한번쯤은 골머리를 앓아보았을것이다. 대부분 입문자들은 컴퓨터 구조에 대해 전혀 모르는 상황에서 C를 배우기 때문. 하지만 포인터를 제대로 사용할 수 있게 되면, 그시점에서 컴퓨터 위주로 생각할 수 있게 된다고 볼 수 있다. 그렇기 때문에 사실상 컴퓨터 구조와 함께 배우는 셈이 되는데 기본지식이 없는 일반인의 머리로는 이게 제대로 될리가 없다. 포인터 덕분에 메모리어셈블리어 수준으로 정밀하게 제어할 수 있지만 그 반작용으로 에러의 90%는 궁극적으로 포인터 문제다.[30] 때문에 C#이나 자바 등은 포인터를 지원안한다.[31][32](결국 구조체와 배열 참조도 전부 포인터 참조로 이루어 진다. 다만 사용자에게 제공하지 않을 뿐이다.)

포인터는 정말 어렵다! 하는 인식은 과장되어 있는 측면이 크다. 개념자체는 주소를 저장하는 변수이지만, 입문자에게 포인터가 벽으로 느껴지는 것은 첫번째로 맞닥뜨리는 생소한 개념이기 때문이다. 그 전까지 간단한 논리 체계를 배우는 수준이었다면 포인터는 본격적으로 컴퓨터의 구조를 공부하게 되는 시점. 게다가 문제는 그 개념이 아니라 응용에 있어 허들이 높다. 제대로 관리하지 않으면 메모리 누수가 일어나고 잘못된 주소를 가리키거나 하는 등 본격적인 디버깅 지옥문그대신 등가교환으로 디버깅 스킬업. 게다가 여러가지 비정상적인 방식으로 포인터를 사용하는 스킬들도 많기때문에 사실상 끝이 없다. 사실 프로그래밍에 있어서는 필수적인 개념이며[33], 이를 이해하지 못하면 자신의 프로그래머로서의 능력을 의심해봐야한다.[34] 다른 객체지향언어를 놔두고 C를 익히는 이유 중 하나는 궁극적으로 포인터를 사용하여 쉽게 개발을 하겠다는 의도이다.[35] 하지만 일반인 사이에서는 이러한 C의 장단점을 무시한채 그냥 프로그래밍 입문으로 적절하다는 식으로 주입하고 있다무슨지거리야.

포인터의 악명은 DOS 시절로 거슬러 올라간다. DOS 시절은 16비트 CPU[36]의 한계로 포인터도 near 포인터(2바이트), far 포인터(4바이트)로 나뉘어져 있었는데 이 시절에는 저 포인터들을 다 컨트롤하기가 쉽지 않았다(주소 계산 방식부터 다르다). tiny, small, medium, compact, large 등등의 메모리 모델이 있었고 각각의 모델마다 사용되는 포인터가 달랐다. data segment 가 한개뿐인 모델에는 near 포인터를 사용하였고[37], 그 외의 보다 큰 메모리 모델에는 far pointer 가 사용되었는데 당연히 near pointer 가 오버헤드가 적기때문에 가급적이면 작은 메모리 모델을 골라서 사용하였다. 게다가 포인터가 깨지기라도 하면 아예 컴퓨터가 맛가는 경우도 많았기에 디버깅 지옥이었다. 본격적으로 32비트 시대가 열리고 난 이후[38]에 near, far 개념이 사라지고 메모리 관리를 OS차원에서 어느정도 관리해주면서 포인터 지옥에서 상당히 해방되었음에도 불구하고 과거의 포인터의 악명이 그대로 이어져 오고 있는 것이다. [39] 물론 드라이버와 같은 Low-Level 프로그램을 짠다면 포인터 한번 잘못 사용하는것으로 블루스크린 을 심심찮게 맛볼 수 있다. 블루스크린이라도 나오면 이는 매우 양호한 경우이고, 조금 안 좋으면 시스템 정지, 최악의 경우는 어떠한 반응도 없이 바로 재부팅이 되는 경우이다. 사실 시스템 정지가 일어나는 경우는 동기화 객체를 잘못 다루었을 때에 발생하는 경우가 많다만

C에 입문하는 대학생들에게 필요이상의 심리적 부담을 안겨주어 시작하기도 전에 지레 겁부터 먹게 만드는 악효과를 가져왔다. 여기에 교수들의 실력 부족과 잘못된 커리큘럼은 포인터를 더욱 큰 벽으로 느끼게 만들고 있다. 이 문제는 십여년이 흘렀어도 개선되지 않고 결국 난이도가 좀 더 낮은 언어인 자바로 프로그래밍 교육 커리큘럼이 이동하는 추세다.[40] 자바를 새로 배우기 귀찮아하는 교수들은 이마저도 못하지. 아 대학원생을 족치면 되겠구나! 자바를 비롯한 현대 언어들은 포인터를 아예 없애 메모리에 직접적인 접근을 막고 그 자리에 참조자를 넣어서 자동으로 관리를 한다.[41] 자세한 건 자바 항목 참조.

어렵다는 단점이 있지만 포인터는 강력한 도구임을 알수 있다. 시스템 내부에서도 굉장히 많이 사용되며 크고 긴 문자열 값을 일일이 넘겨줄 필요 없이 포인터 하나만으로 대체 할수 있으며 알고리즘, 자료구조에도 많이 사용된다. 배열이나 구조체 참조에도 포인터를 사용하게 된다.

만약, 아무리 생각해도 당신이 포인터에 대한 이해가 어렵다고 생각된다면 다음과 같이 생각해보도록 하자. 우리가 컴퓨터를 켜면 바탕화면이 나오고, 거기에는 수많은 바로가기 아이콘이 존재하며 바로가기 아이콘은 반드시 어떠한 원본 파일을 가리키고 있으며 바로가기 아이콘이 가지는 데이터는 그 원본파일의 실제 절대경로이다. 포인터도 마찬가지로, 포인터변수(바로가기 아이콘)는 어떠한 원본 데이터(원본 파일)를 가리키고 있으며 포인터변수가 가지고있는 데이터는 원본 데이터의 위치를 가리키는 메모리 어드레스(원본파일의 절대경로)이다.[42]

그래도 포인터가 너무나도 블랙홀처럼 느껴진다면 그냥 어셈블리어를 아주 기본적인 부분만 어느정도 공부해보는것이 낫다. C 언어에 비해 훨씬 직접적으로 메모리를 다루고 포인터 개념도 그와중에 많이 사용하기때문에, 대충 사용법만 짚고 넘어가는 경우가 많은 C 언어 교재들에 비해 설명도 하드웨어와 더불어 훨씬 자세한 경우가 많고, 어셈블리어와 어느정도 씨름하다보면 C 언어의 포인터는 그냥 저절로 이해가 된다. 어셈블리어까지 보는게 거부감이 들 수도 있겠지만, 고급기능들은 배제하고 기본적인 부분으로 한정하면 사실 아주 단순하고 시간도 얼마 걸리지도 않는다. 어셈블리어를 보다보면 C 언어가 얼마나 하드웨어와 가까운 언어인지도 실감이 날것이다.


4.1. 중괄호 스타일


C언어는 스코프를 지정할 때 중괄호 쌍을 { } 사용한다. C언어는 whitespace(공백, 탭, 리턴 문자열)가 의미 없는 언어라서 여는 중괄호를 엔터를 쳐서 다음 줄에 놓는 방법과, 이전 표현 바로 옆에 놓는 방식 두 가지 모두 가능하다. 이런 두 가지 스타일을 각각 Allman [43] 스타일과 K&R스타일 [44] 이라고 한다.

소스로 보자면 다음과 같다.
  • K&R 스타일
아래와 같이 while, if 문 등의 옆에 여는 괄호가 붙어 있다.
int main()
{
    while (x == y) {
        something();
        somethingelse();
 
        if (some_error) {
            /* the curly braces around this code block could be omitted */
            do_correct();
        } else
            continue_as_usual();
    }
 
    finalthing();
}

  • Allman 스타일
아래와 같이 while, if문 밑에 여는 괄호가 있다.
int main ()
{
    while (x == y)
    {
        something();
        somethingelse();
 
        if (some_error)
        {
            /* the curly braces around this code block could be omitted */
            do_correct();
        } 
        else
            continue_as_usual();
    }
 
    finalthing();
    ...
}

각각의 스타일은 장단점이 있는데, K&R 스타일은 여는 중괄호에 엔터를 치지 않기 때문에 적은 줄 수에 더 많은 내용을 담을 수 있는 반면 중괄호 블록이 눈에 잘 안 들어오는 단점이 있다. 반면에 Allman 스타일은 여는 위치와 닫는 위치가 같기 때문에 중괄호 블록이 명료한 반면에 수직적으로 많은 공간을 차지하는 단점이 있다. 그래서 지문을 많이 넣고 싶지 않은 C언어계 책의 9할쯤은 전부 다 K&R 스타일이다. 반면 실제 코드의 스타일은 4할-4할 정도. 예제는 K&R 스타일로 쓰고서도 본문 중에 실제 작업에서는 Allman 스타일을 쓴다고 밝히는 저자도 있다. 2할은 기타 스타일.

4.2. 장점

4.2.1. 과거

C가 나올 당시 시점에서 당시 널리 쓰이던 포트란이나 코볼, 베이직과 비교해 보자면, C는 언어 자체에는 아주 기초적인 기능 만을 탑재하여 언어에 기본 탑재되는 명령어를 최소한도로 줄였다는 특징이 있다.

C에서는 START나 END같은 명령어도 배제하고, 대부분을 { } 같은 기호로 표현했기 때문에 코드가 매우 깔쌈하고 용량도 줄었다. C에서는 포트란에는 아직 남아 있던 천공카드 시대의 흔적이 거의 사라졌다.

4.2.2. 현재

현재 시점 기준으로 C의 주요한 특징은 현대 주류 언어 중 거의 유일한 네이티브 컴파일 언어라는 것이다. 자바파이썬 등은 다 가상머신 위에서 실행이 되는 반면, C/C++는 기계어로 바로 컴파일된다. 따라서 현대 고급 언어들과 단순 비교하기엔 포지션 자체가 다르다고 할 수 있다. 가상머신 자체가 C/C++로 만들어지니깐… 어쨌든, 매우 속도가 빠르고 코드가 작지만, 컴파일 시간이 오래 걸리며 디버깅도 어려워 생산성이 비교적 낮다. 이러한 특성 때문에 속도가 다른 무엇보다 (심지어는 생산성보다도) 중요한 임베디드 혹은 모바일 계열, 또는 시스템 프로그래밍 등에서 주로 사용된다. 그러나 모바일의 경우도 이미 하드웨어가 발전하여 제약이 많이 풀린 상태이며 생산성을 중요시하는 추세로 가고 있기 때문에 C가 설 입지는 점점 좁아지고 있다. 실제로 현재 시중에 판매되는 휴대 전화에 WIPI-C의 컴파일러 및 링커 설정을 고쳐서 C++을 사용하게 할 수 있는데 문제가 될 만한 속도 저하는 없었으며 여러 나라의 BREW시스템에서도 C++로 인해 속도 문제가 생긴 적은 없다. 더군다나 최근 인기있는 안드로이드 운영체제 같은 경우 기본적으로 Java를 사용해서 개발하도록 되어 있다.[45]

이러저러한 고급 언어들이 나오는 상황에서도 아직 저수준의 제어를 위해 C가 필요한 경우도 많다. 예를 들어, OS를 만든다면 아무리 생산성을 고려한다고 해도 시스템 제어 측면과 OS의 기능들 위에서 돌아가는 어플리케이션 때문에라도 속도라는 면은 중요하고[46], 그렇다고 속도를 높이기 위해 어셈블리어나 기계어로만 OS를 짜기에는 생산성이 매우 낮아지기 때문에, 타협점으로 C를 쓴다. 물론 시스템 콜 인터페이스나 ABI, 인터럽트, 부트 스트랩, 드라이버 등 머신에 직결된 부분에는 어셈블리나 기계어를 사용해야 한다. 아니면 머신 제조업체가 제공하는 라이브러리를 사용하거나.

또한 대부분의 운영체제가 제공하는 API 혹은 시스템 콜은 C 기반이기 때문에 이를 직접 사용하려면 어찌되건 C를 래핑하는 방식으로 밖에 쓸 수 없다. 그 외에 임베디드 시스템에서 단가 문제로 시스템 처리 능력과 메모리 제한이 매우매우 심각한 경우가 많은데 이 경우도 C가 그나마 적합하다. 이렇게 활용되는 부분이 많으므로 당분간은 사장될 가능성은 없다. 게다가 막대한 분량의 레거시 코드도 있고. 실제로 프로그래밍 언어 점유율 조사에서 한때 자바에 밀렸다가 다시 자바를 제치고 다시 1위를 차지하는 것을 보아서는 당분간 현역으로 왕성하게 활동할 것으로 보인다. C의 점유율이 늘어났다기보다는 타 현대적인 언어들 덕분에 자바의 점유율이 줄어든 거지만.

안정성보다는 퍼포먼스를 골수까지 뽑아내야 하는 게임 프로그래밍 분야 또한 C/C++가 대세. 게임 프로그래머들이 C에서 C++로 넘어가기를 끝까지 싫어했던 것은 오로지 C(지금은 C++)가 다른 언어보다 속도를 빠르게 최적화할 수 있기 때문이며, 다른 분야에 비해 보수적이라는 소리를 듣는 편. 요즘에는 코어부분만 C/C++ 로 만들고, 게임 로직의 상당한 부분을 다른 고급 스크립트 언어에 의존하는 추세. 사실 게임 분야 뿐만이 아니고 대규모 프로젝트에서 퍼포먼스 문제 등으로 코어는 C/C++로 짜고 UI, 스크립트 등의 서브 시스템을 고수준 언어를 쓰는 패턴이 많이 사용된다.

속도와 시스템 제어가 필요한 코어 부분은 다들 C/C++로 제작하고 UI나 콘트롤러같은 건 고급 언어를 쓰는 게 현상황. 옛시절 어셈블리어가 차지했던 자리를 현재는 C가 차지하고 있다고 봐도 된다.

현시점에서 C의 가장 큰 의의는 다른 많은 언어들의 모체가 되었다는 것과 더불어 거의 모든 시스템과 운영체제에서 지원하는 언어라는 것이다. C++은 지원하지 않더라도 C는 지원하는게[47] 보통. 그런 관계로 이식성이 중요한 경우는 대개 C를 사용한다. 자바의 멀티플랫폼과는 성격이 다르다. 자바는 각 플랫폼용으로 만들어진 가상머신 위에서 같은 소스가 실행되는 것이고, C의 경우는 각각의 시스템에 맞는 기계어로 컴파일 되는 것이다. 위에도 언급했던 자바 가상머신 자체가 C/C++로 만들어지므로 당연히 자바보다 범위가 넓다. 기존 C 프로그래머들은 진정한 멀티 플랫폼 언어는 자바가 아니라 C 라고 믿는 사람도 부지기수. 표준만 철저하게 지킨 C 코드는 C 컴파일러가 있는 어떤 플랫폼에서도 컴파일 - 실행이 가능하다.[48] 그게 쉽지 않아서 문제지. 요즘 C를 사용하는 이유는 위에도 쓰여있듯이 저수준의 제어가 필요하기 때문에 사용하는데, 이는 플랫폼에서 제공하는 API를 사용하지 않고는 불가능하기 때문.

이렇게 이미 한물 간 언어처럼 보이지만, 여전히 '프로그래밍' 입문으로 C를 추천하는 사람이 많다. 사실, 이 말에도 일리가 있긴 한것이 C라는 언어는 매우 심플하면서도 배우는 과정중에 소프트웨어 구성의 최소단위인 bit부터 시작해서 메모리 관리, 그리고 고급 개념인 oop 비스무레한것까지[49] 흉내내면서 소프트웨어 전반을 훑게 되고, C 를 배우는 과정중에 나오는 과제들은 커맨드라인에서 이미 쓰이고있는 기본적인 툴들을 reinvent the wheel[50] 하는식의 과제들이 많기때문에 바닥부터 훑어가며 견문을 넓히는데 좋다. 실제로 가장 기저에 놓인 OS API[51] 는 오늘날 플랫폼을 불문하고 거의 다 C 언어로 되어있고, 그외에도 대부분의 인프라가 되는 소프트웨어들은 C로 만들어진 후 타 언어로의 바인딩을 제공하는식이다. 로우레벨부터 단계를 높여가며 관찰을 해보면, 머신코드는 머신에 따라 달라지고, 어셈블리어도 Intel/AT&T 등 문법에 따라 몇가지 버전이 존재하지만, 그 위쪽에서 결국 C 언어로 대통합이 이루어진다. 그리고, C 언어 위쪽으로 가면 다시 C++/Java/C#/Objective-C/Python 등으로 다양하게 갈라진다. 즉, 두개의 원뿔을 꼭지점끼리 붙여놓은 double cone 형태이며, 저 꼭지점 부분에 C 언어가 존재하는 형태이니 이것만으로도 C 언어의 중요성은 충분히 알 수 있다. 그렇기때문에 이런 견문은 실제로 나중에 더이상 C 언어를 쓰지 않고 타 고급언어로 넘어가더라도 유용한 경우가 많다.(실제로, 많은 수의 언어가 C 언어와의 FFI를 제공한다.)

다만, 요즘 대학에서는 신입생들 프로그래밍 입문 강의로 C 언어를 기피하는 현상이 있는데, 대학은 '특정 프로그래밍 언어'를 배우거나 '프로그래머'를 양성하는 기관이 아니기 때문이다. 실제로 해외대학들은 C 언어를 입문강의로 사용하는곳이 거의 씨가 말랐다. 그리고, 그 이후에도 모두가 C 언어를 배우는것이 아닌, 하드웨어쪽으로 방향을 정한 학생들만 C 언어를 배우는 경우가 많다. 사실 오늘날 컴퓨터는 수학(논리학)과 전자공학의 중간즈음에 위치한 분야라 할 수 있는데, 해외에서는 학풍에 따라 프로그래밍 입문 강의를 순수수학/논리학과 가까운 Programming Language Theory 의 입문으로 생각해서 가르치거나 혹은 보다 실용적인 전반적인 소프트웨어 개발경험정도로 생각해서 가르치는 경우가 많다. 그리고, 전자의 경우에는 언어적으로 볼때 너무나 심플해서(그냥 하드웨어를 그대로 노출시킨듯한 디자인의) 아무런 매력이 없는 C 언어를 사용할 이유는 거의 없으며, 후자쪽도 소프트웨어 개발 전반을 최대한 많이 경험할 수 있게 해주는것이 목적인데, C 언어의 경우 한학기동안 배워서 커맨드라인 입출력만 끄적이는게 고작이다보니 이 역시 한학기 배우는 과정중에 어느정도의 OOP 개념도 맛볼 수 있는 자바나, 한학기만 배우면 학생들 스스로 어느정도 괜찮은 프로젝트를 진행할 수 있게 되는 파이썬에 비하면 크게 밀린다.

실제로, 대학에서 C 언어를 프로그래밍 입문으로 배울 경우, 그 강의는 프로그래밍 강의라기보다 순수한 C 언어 강좌가 돼버리는 경향이 있다. 예를들어, char p[] = "aaa"; *p = 'b'; 는 문제가 없는데 char *p = "aaa"; *p = 'b'; 는 런타임 에러가 난다. 문자열, 포인터, 배열 관련해서 프로그래밍 개념적으로는 거의 의미없는 그냥 C 언어만의 저런 함정들이 상당히 많은데다가, 코딩시 자주 접하게 되는 결코 무시할 수 없는 함정들이기때문에 그냥 넘길수도 없고 거기에 낭비되는 시간도 은근히 많다. 대학 프로그래밍 강의의 목적을 생각하면 사실 무엇이 더 적합한지는 자명하기때문에, Java, Scheme, Python, ML, Haskell(!) 등 해외대학의 경우는 프로그래밍 언어 입문이 거의다 고수준 언어로 변경되었다. 한국의 경우는 순수수학이나 논리학같은 분야가돈이 안되다보니 기반이 매우 약한편이며, 반면 공학은 기형적으로 발달해있기때문에 전자공학쪽의 입김이 센편이라 여전히 대학에서 C 언어로 입문을 시키는 경우가 많다. 심지어 대학교에서도 고급 컴퓨팅 하면 로우레벨쪽부터 상상하는 사람들이 대부분이고, 입문강의를 C 언어에서 다른걸로 바꾸는 이유가 C 언어가 어려워서 잘 못따라오니 쉽게 가르치기 위해서라고 착각하는 사람도 많은편.

5. 점유율과 플랫폼별 지원상황

Example.jpg
[JPG image (Unknown)]

출처 : 매달 자료가 업데이트되므로 참고할 것.

2014년 11월을 기준으로 자바와 함께 몇년째 1, 2위를 다투고 있으며, 그 이외의 언어랑은 넘사벽의 비율을 보여준다. 그야말로 부동의 원투펀치. 다른 언어들이 3위 경쟁을 하는동안 C와 자바가 넘사벽 양대산맥을 보여 준다. 특이할점은 점유율이 하락세를 타다가 최근에 오히려 올랐다는것인데, 아마도 애플 붐에 힘입어 초고속 성장세를 타고있는 Objective-C 의 영향을 좀 받은듯 하다.[52]

가장 널리 쓰이는 PC 플랫폼인 윈도우에서는 안타깝지만 반쯤은 버려진 언어이기도 하다. MS 에서는 C를 Internal language로 규정하여 내부적으로 윈도우와 기타 MS 상품들을 만드는데는 사용하지만, C 프로그래밍 환경을 사용자에게 정식으로 제공하지는 않는다. 덕분에 윈도우가 자랑하는 비쥬얼 스튜디오 에도 C 프로젝트 항목은 없다.(C++ 프로젝트를 선택하여 소스파일 확장자를 .c 로 바꿔주거나 C 로 컴파일한다고 프로젝트 옵션을 설정해야 한다.) 게다가, 그런식으로 사용을 하더라도 MS 의 C 지원은 순수하게 C++ 에 묻어가는 정도라, 새로운 ISO 스탠다드인 C99/C11 의 기능들도 거의 지원하지 않으며, 앞으로의 계획도 C99/C11을 완전히 지원할 예정은 전혀 없고, C99/C11의 기능중 C++98/C++11에도 포함되는 것만 지원할 예정이다.

리눅스 의 경우에는 gcc 라는 사실상의 오픈소스 표준 컴파일러 덕분에 지원이 괜찮으며, 유닉스 운영체제라는 버프도 있고[53], C를 배우고 여러가지 시험해보면서 놀기에 적합한 환경을 제공해준다. 윈도우와 다르게 커널부터 오픈소스로 개발되고, 이 커널이 C 언어로 만들어져있기때문에 C 언어의 사용도 활발한편이다. 이쪽 프로그래머들은 개발환경을 vim이나 Emacs로 사용하는 사람들이 많이 있다.

맥 OS X 는 신생 컴파일러인 Clang[54]을 사용하며, 역시 지원은 좋은편이다. 이는, 플랫폼 메인 개발언어를 Objective-C로 잡았기때문인데, Objective-C는 C 언어와 완전히 호환이 되기때문에 달랑 Objective-C만 지원해도 C 가 완전히 지원되는셈. 새로운 스탠다드의 적용도 세 플랫폼중 가장 빠르다. MS 는 위에서 이야기했듯이 C++ 의 subset 인 부분에 한해서만 지원을 하고, gcc 와 맥 OS X 의 개발환경인 Xcode 에서는 C11을 지원한다.


6. 다른 언어에 미친 영향

  • { ... }을 이용한 블럭 (ALGOL/PASCAL 스타일의 begin ... end 보다 간결하다)
  • 대입을 뜻하는 연산자를 =로, 동일함을 뜻하는 연산기호를 ==로 사용한다. 농담 좀 섞어서 초심자의 C언어 코딩 에러의 90%는 여기서 나온다.[55]
  • 다르다를 뜻하는 연산기호를 !=로 사용한다.
  • or/and를 ||와 &&로 사용한다.
  • +=, -=, *=, /=등의 직관적인 복합연산자를 지원한다.
  • 그외에 if, for, while 등 많은 예약어의 사용 방식

어떤 의미에서는 프로그래밍 언어의 라틴어/한자라고 할 수도 있을지도 모른다. 현재 많은 주요 언어에서 { }를 이용한 블럭 표기나 C에서 쓰이는 표현식(==, ||, &&), 예약어(if, while)등등을 채택해서 사용하고 있다. 따라서 다른 언어를 배울 때 C언어를 먼저 배웠다면 친숙하게 느껴질 것이다. [56]

추후 C++로 발전되었으며, C++에서는 OOP 기능을 부분적으로 지원한다. 그러나 C가 객체지향 언어가 아니라는 말은 틀린 말이다. 객체지향은 개념일 뿐이며 C로도 그 개념을 구현할 수 있다.(물론 코드가 불어나는 것은 어쩔 수 없다.) 일례로, Win32 API가 C로 구성된 객체지향 프레임워크이다.[57]

자바나 C#, Objective-C 등 여러 언어의 모태가 된다. 때문에 C를 기초로 만들어진 언어들을 흔히 C like Language라고 부른다. 그런 이유로 C를 제대로 익히고 나면 C like 언어들은 쉽고 빠르게 익힐 수 있다. 단, 위에서 이미 언급했지만 C 자체는 엄청나게 어렵다.
그대신 C나 C를 모태로 한 언어를 공부하면 자연스럽게개고생을 해가며 컴퓨터와 프로그램의 작동방식에 대한 기초 지식을 습득할수 있어 다른 언어나 프로그래밍 관련 스터디를 할때 도움이 된다.뇌개조의 축복

덕력이 충만한 사람들을 위한 설명을 하자면 야쿠시지 료코가 프랑스어 영어에 모두 통달한 이유?

"라틴어를 익히면 영어 프랑스어 모두 쉽게 익힐 수 있어."
라틴어>>>>영어+프랑스어인것은 그냥 넘어가자.

7. C 언어용 컴파일러/개발 도구들

  • Bloodshed Dev-C++ 공식 페이지
    GPL 라이센스를 따르는 개발 환경. 2006년 이후로는 소식이 없다.

  • Orwell Dev-C++ 공식 페이지
    orwell이 Bloodshed Dev-C++ 4.9.9.2 소스로 개발하고 있는 dev-c++이다.

  • Borland C 지원 페이지
    지원 페이지만 남아있을 뿐이고 구입하는 곳은 여기로 링크되어 있다.[58]

  • Code::Blocks 공식 페이지
    오픈 소스 개발 환경이며 라이센스는 GPL 3.0 버전을 따르고 있다.

  • Microsoft C 지원 페이지
    MS 는 C 를 Internal language 로 규정하여, Windows 나 기타 MS 소프트웨어 개발에 사용하기는 하지만, 엔드유저[59]에 지원하지는 않는다. 다만, 비쥬얼 스튜디오는 C++ 을 지원하며, 이 언어가 C와 상당부분 유사성이 있기때문에, 여기 묻어가는 형식으로 이용은 가능하다. 즉, 제대로 사용하려면 다른 C 컴파일러를 따로 깔거나 그냥 유닉스 플랫폼을 따로 인스톨하는 것이 낫다.

  • 비주얼 스튜디오[60] 한국어 공식 사이트

  • Pelles C 공식 페이지
    윈도우 전용의 프리웨어 개발 환경이다. MS 와는 다르게 C99 는 물론이고, 현존 거의 유일한 C11 완벽지원 컴파일러를 제공한다.

  • Turbo C 공식 페이지
    Borland C와 마찬가지로 공식 페이지만 남아있다. 역시 판매는 여기에서 담당하는 듯하다.

  • Watcom C 공식 페이지
    공식 페이지가 위키위키 형식으로 되어 있다. Open Watcom Public License 라는 라이센스를 따른다고 한다.

  • Wipi C
    관련 문서: WIPI

  • GNEX

  • 이클립스 CDT 공식 페이지

  • GCC

  • Xcode 공식 사이트 애플에서 직접 제작하는 IDE. 예전에는 위의 GCC를 그대로 가져다[61] 썼지만, 요즘은 LLVM이라는 신세대 컴파일러셋으로 이주하는 중이다[62]. C, C++, Objective-C 등의 언어를 컴파일할 수 있다. OS X용 애플리케이션이나 iOS용 앱을 제작하는데는 필수.

  • LLVM/Clang 공식 사이트 위에서 LLVM 을 언급했는데, LLVM은 백엔드이고, 실제 C 컴파일러는 프론트엔드인 Clang이 담당한다. 신생 컴파일러이지만, 애플이라는 든든한 빽을 동반하고 급성장중이다. 컴파일속도는 gcc 보다 빠르지만, 런타임 속도는 아직 좀 떨어진다. 신생 컴파일러인만큼 gcc에 비해 구조가 깔끔하여 차후 발전가능성이 높다고 한다. 곧 gcc 와 맞짱뜰 수준으로 발전할 가능성도 있다. gcc의 라이센스를 마음에 안들어하는 FreeBSD 버전 10 에서 기존 구버전 gcc 4.2를 밀어내고 디폴트 컴파일러 자리를 차지하였고, 애플의 OS X 매버릭스에서도 마지막까지 남아있던 llvm-gcc를 제거하며 완전히 자리를 차지하였다. 더불어 현재 C++ 최신표준의 지원도 가장 빠르다. MSVC가 C++11의 지원도 지지부진한 마당에 Clang은 이미 C++14까지 feature complete 인 상황.


----
  • [1] 처리할 데이터의 양이 커지면 처리 속도가 지나치게 증가하는 알고리즘.
  • [2] Structure And Interpretation Of Computer Programs. MIT에서 만든 컴퓨터과학의 고전과도 같은 책이다. 이 책도 현장에서 바로 써먹을 수 있는 러시아공 페인팅 코딩을 가르치기보다는 프로그램이 어떻게 구성되는지의 원리를 이해하고 거대한 프로그램의 복잡성을 효과적으로 컨트롤하는 내용을 가르치는 책이다. 때문에 근본부터 가르친다는 측면에서 위와 비슷한 동기를 지닌다.
  • [3] 과거 새로운 표준이 200x 년에 나올줄 알고 C0x 로 불렸으나, 2011년에 등장하여 C11 이 되었다. C++ 역시 같은 이유로 C++0x 로 불리다가 2011 년에 등장하여 C++11 되었다.
  • [4] 이들은 다른 언어가 아니라 버전이 다르다.
  • [5] 물론, 금기라 해서 완전히 없던것은 아니다. 당장 유닉스의 전신이던 MULTICS 부터 PL/1 라는 고수준 언어로 작성되었다.
  • [6] 물론 믿으면 곤란. 이쪽은 추상화느님으로 마치 자연어처럼 읽히는 코드를 써서 주석 자체를 코드로 최대한 대체해서 주석이 코드의 변화를 못따라가는 불상사를 방지하는 것이다.
  • [7] 주의해야할것은, K&R C 와 착각하면 안된다. 인터넷에서 검색하면(주로 C 역사) K&R 이라는 단어를 K&R C 를 지칭하며 사용하는 경우도 가끔 있다. K&R C 는 ANIS C 이전버전의 '언어'이고, 현재 이 페이지에서 칭하는 K&R 은 C 교재이며, K&R 1st Edition 은 K&R C 의 교재이고, 본문의 K&R 2nd edition 은 업데이트된 ANSI C(C89) 교재이다.
  • [8] 사실 ANSI C 다음 버전부터는 90% 이상의 점유율을 담당하고 있는 MS 에서 캐무시하고 있는 영향도 크다.
  • [9] 여기에 관해서도 혼동이 있을 수 있는데, 이후 ANSI가 C 표준 제정에서 손을 떼고 ISO 의 그것을 받아들였기 때문에, 공식적으로 ANSI C 는 최신표준인 C11 을 가리킨다. 하지만, 실제 사람들이 ANSI C라 지칭할 때는 ANSI가 표준을 직접 제정한 C89/90를 의미한다. 이 페이지에서도 ANSI C는 C89/90를 의미한다.
  • [10] 최근 C++11로 업데이트된 4차 개정판에서 드디어 1000 페이지의 벽을 깨고 1300 페이지를 넘겼다.
  • [11] 실제로 아주 중요한 내용이 구석탱이에 딱 한줄 써 있는 경우가 많다.
  • [12] 그렇기에 더더욱 초심자에게는 어울리지 않는다.
  • [13] 어차피 저런걸 모두 담고있는 교재가 없긴 하지만, 더하고 덜하고 정도의 차이는 있게 마련이고, 그 차이는 나중의 삽질과 시간낭비로 반드시 뿌린대로 거두게 된다.(..) 물론, 웹에 널려있는 정보들을 복붙하는식의 습득도 가능하지만, 잘못된 정보인 경우도 많고 그 설명이 제대로된 교재 수준을 넘어가는 경우도 드물다. 또한, 같은수준의 지식이라면 웹서핑보다 교재로 배우는편이 효율도 훨씬 높다.
  • [14] 초기 C 언어는 커다란 규모의 프로그램을 거의 염두에 두지 않고 개발되었다. 당시 IBM 메인프레임에 사용되던 System/360 이 수천명의 프로그래머가 달라붙어 어셈블리어로 수백만줄이었는데, C 언어로 만들어진 가장 큰 프로그램인 초창기 유닉스의 커널은 고작 만줄정도였다.
  • [15] 인력도 인력이지만, 당시 머신은 초고도로 최적화를 해야 만족할만한 속도를 보여줬다. 덤으로 C언어 그 자체도 컴파일러를 거쳐 기계어 파일이 나오면 그걸 다시 사람이 직접 최적화를 해 줘야 했다고 한다. 당시 컴파일러의 최적화 성능이 떨어졌던 이유도 있겠지만
  • [16] 그 때문에 3부터 arr 포인터 만큼 떨어져 있다는 뜻의 3[arr]는 arr[3]과 정확하게 동일하다. 사실이다. 사실, a[i] 는 그냥 *(a+i) 의 축약형이다. 그러니, a[i] == *(a+i) == *(i+a) == i[a] 가 된다.
  • [17] 배열 경계 좀 넘는다고 뭐 그리 대단한 일이 일어나겠냐고 물으신다면, 배열 경계를 넘기면 그 위에 선언한 변수들을 하나하나 덮어쓰기가 되고, 최종적으로 리턴 어드레스(함수의 실행을 끝낸 후 다시 함수를 호출한곳으로 돌아가는 주소값)까지 덮어쓰는게 가능해진다. 기본적으로 이 취약점을 가진 프로그램을 네트워크에 물리면 원하는 동작을 원격에서 실행시킬 수 있게 되며, 최악의 경우는 루트 권한으로 실행되는 프로그램에서 리턴 어드레스를 쉘을 실행하는 코드가 있는곳으로 덮어쓰면 루트 계정을 원격으로 탈취당할 수도 있다. 1998 년 전세계 서버를 감염시킨 모리스 웜도, finger 라는 유닉스 유틸리티의 버퍼 오버플로우 취약점을 이용하였다. 이 웜은 쉽게 들통나지 않도록 여러가지 카모플라쥬 전략이 많이 포함되어있었고, 코넬대학은 결국 서버를 다운시키는등의 조치를 취했지만 전세계로 퍼져나갔다. 당시 이 웜을 만든 23세의 모리스는 벨 연구소에서 유닉스의 로그인 암호화를 담당했던 사람의 아들이었고, 현재 MIT 대학의 교수이다. 2001년 한국에도 사이버 대란을 일으킨 코드레드 의 경우 전세계의 서버 몇십만개를 감염시킨 사례가 있다. 이 취약점 때문에 경계 체크를 안하는 gets 같은 표준 함수 여러 개를 depreciated(사용 자제) 시켜야 했고, printf의 포맷 문자(%n) 하나가 날라갔다. 심지어 운영체제 자체에서 buffer overflow 방지 메커니즘을 제공하기까지 하는 데도 간간히 뚫리는게 이 취약점이다(..). 물론 공돌이들이 손 놓고 있는게 아니니 방지책도 많이 마련되어있긴 하지만 그럼에도 뚫릴 취약점은 뚫린다. 2014년 OpenSSL에 생긴 재양적인 버그인 하트블리드도 근본적으로는 C언어가 배열의 경계를 체크하지 않는다는 점에서 생겼다.
  • [18] visual studio 2012 버젼부터 함수에 _s 가 붙은 (printf_s, scanf_s 등) 보안을 위한 함수가 추가 되었다. 기존의 printf 같은 함수는 그냥 쓸 수 있지만 scanf와 같은 함수를 쓰려고 하면 보안에 따른 에러 메시지가 뜬다(...)
  • [19] 다른 타입들에 대해서는 예를 들어 int i, *j = &i; *j = 3; 식으로 해당 포인터가 가리키는곳에 있는 '값'을 의미할때는 항상 * operator 를 붙여줘야 하지만, 문자열일경우에는 char *s; s = "Hello"; 처럼 포인터임에도 불구하고 * operator 를 사용하면 안된다. 실제로, 이 경우, *s 는 s[0] 과 같은 문자 'H' 를 의미한다.
  • [20] void* 가 아니라 char* 었기때문에 malloc 시 항상 캐스팅을 해줘야 했었다. 현재는 void* 가 사용되면서 malloc 시 자동으로 해당 타입으로 캐스팅이 되고, 굳이 캐스팅을 사용할 필요가 없지만 프로그래머의 스타일에 따라 지금도 계속 캐스팅을 해주는 것을 선호하는 프로그래머들이 있다.
  • [21] 예를 들어, int a = 42; if(a == 37) { ... } 같은경우, 실수로 if(a = 37) 이라 쓰면 false가 아닌 true가 뜨며(a = 37 이라는 expression의 값은 37 이고 0 이 아닌 값은 죄다 true로 간주된다.), a에 37 이 대입돼버려 완전히 오작동을 하게된다. 문제는, 컴파일이 문제없이 되기때문에 버그찾기가 더더욱 힘들어진다. 하지만, 상수항을 lvalue에 사용해서 if(37 == a) 로 써주면, 실수로 37 = a라 썼을때 상수항에 대입연산자가 사용되었기때문에 컴파일시 에러가 떠서 쉽게 알아챌 수 있다.
  • [22] 초창기에는 이런 문제로 가독성을 포기하고 컴파일 에러를 검출하기 쉬운 식을 많이 썼지만, 요새는 컴파일러가 좋아져서, 이런 위험코드는 대체로 경고처리해준다.
  • [23] C99 에서 _Bool타입이 생기긴 했다. stdbool.h 를 포함할 경우, 그냥 bool로 사용도 가능하긴 하다. 왜 그냥 bool로 안넣었냐면, 기존 프로그램중에 bool 이름을 사용한 코드가 있을 가능성이 있기때문. 반면, 언더스코어 _ 뒤에 대문자가 오는 이름은 C 표준에서 사용하지 말라고 먼저 명시해놨기 때문에 이것을 사용한 _Bool 이 되었다.
  • [24] 음수도 true로 처리된단 뜻이다. 없으면 define 문으로 선언해서 쓰면 된다.
  • [25] int i='a'; char c='b'+i 같은것들이 매우 자연스럽다.
  • [26] 따라서 char c = 0; 이라고 하면 c에는 '\0'이 대입된다.
  • [27] 간단한 예를 들자면 타입과 배열과 포인터가 혼돈의 카오스가 되는 이유인데, 사실 데이터를 실제 저장장치에 저장할 때 이게 정수인지 문자인지 배열 주소인지 포인터 주소인지는 기재되지 않기 때문이다.(그걸 일일히 기재하는 건 시간과 공간의 낭비고, 쓰잘데기도 없는데다가, 데이터가 그런 단순데이터만 있는게 아니기 때문에 거의 불가능하기까지 하다.) 마치 메모장에는 821021372413이라고 적어놓고 나중에 메모장을 펼쳐서 이 숫자가 무슨 숫자였지.... 하고 해석하는 것과 같다. 그 데이터가 무슨 데이터였는지 정확히 기억하고 알맞게 사용하는 것은 어셈블리에서는 순전히 사용자의 몫이고, 그 때의 전통이 살아있던 C에서는 기본적인 타입같은 건 컴파일러가 처리해주되 사용자가 그런 세세한 부분을 컨트롤할 수 있도록 허용해주는 것이다.
  • [28] 소켓 프로그래밍이 보통 이렇다.
  • [29] char, int, float, double과 같은 기본 자료형에서 유도되는 형태의 자료형으로, 다른 유도 자료형으로는 배열이 존재한다.
  • [30] 특히 링크드 리스트를 배우다 보면 내가 무슨 짓을 하고 있는건지 스스로를 자책할 때가 많다.
  • [31] C#이나 자바의 경우 기본적으로 객체 참조 기반으로 돌아간다. 하지만 참조 관련된 일은 저단계에서 알아서 해주기 때문에 좌우당간 쌩 포인터잡고 낑낑거리기 보다는 쉽다.
  • [32] C#은 unsafe 키워드로 정말정말 간절하게 필요한 경우 유사하게 만들어 사용할 수 있음. Java에도 Unsafe 클래스가 있긴 하지만 팩토리 메소드가 막혀있어 리플렉션을 사용해야만 이용할 수 있다. 게다가 자바에서 굳이 포인터를 직접 관리해줄 필요는 없다.
  • [33] OOP 같은것도 밑바닥은 결국 포인터다
  • [34] 역시나 전산과라면 전과를 심각하게 고려해야 한다.
  • [35] 코어 임베디드 개발 영역에서는 포인터 없이는 아예 못하는 것도 많다.
  • [36] 사실 8비트 CPU도 마찬가지지만.
  • [37] near pointer 는 offset 만 저장한다. data segment 가 한개뿐인 상황에서는 offset 이상의 정보가 필요가 없으니.
  • [38] 사실 32비트 시대에서도 DOS는 호환성 문제로 기본적으로 16비트 프로그래밍을 이용했기 때문에 큰 의미가 없었다. 이 부분은 16비트 버전 윈도우도 마찬가지.
  • [39] Intel CPU에서 16비트 모드의 경우, seg:ofs로 나뉘는데, 이가 가리키는 주소는 addr = (seg << 4) | ofs; 로 표현되며 seg, ofs 둘다 16비트이기 때문에 이들의 값이 달라도 같은 주소를 가리키게 되는 경우가 많다. 예를 들어서, 22eeh:0000h = 22e0h:00e0h = 2200h:0ee0h = ...
  • [40] 몇몇 학교는 아예 MS의 지원을 받아서 C#을 입문 단계에서 강의한다.
  • [41] 하지만 포인터를 배울 필요가 없다는 건 아니다. 간단히 말해, 클래스 변수는 생성과 삭제를 가상머신에서 관리를 해줄 뿐, 그 자체가 포인터이기 때문에, 포인터를 모른다면 자바의 얕은 복사 같은 것은 이해하기 쉽지 않을 것이다.
  • [42] 그냥 눈 딱 감고 8비트때 책꺼내서 Z80 핸드어셈블 3일만 해보자. 명령도 레지스터도 적어서 장난감으로 좋다.
  • [43] 한때 메일서버계의 IE 로 불리던 sendmail 의 저자이며, 게이 프로그래머로 유명한 Eric Allman이라는 사람의 이름에서 따옴. BSD style이라고도 한다.
  • [44] Kernighan&Ritchie의 <The C Programming Language> 에서 쓰여졌기 때문
  • [45] 정확히는 자바는 구현 언어로만 사용하는 것이며, 라이브러리는 전부 안드로이드 SDK를 사용해야 한다. 따라서 JVM 바이트코드를 생성하는 스칼라클로져같은 언어로 코딩하는 것도 불가능한 것은 아니다.
  • [46] 쉽게 말해서, OS의 특정 기능이 느리면 그 기능을 사용하는 어플리케이션들 전부가 덩달아 느려진다.
  • [47] 이유는 컴파일러를 만들기 (상대적으로) 무지 쉽기 때문.
  • [48] 다만, C 표준 자체가 많은 부분을 '모든 컴파일러에 동일하게'가 아니라 구현체에 따라(implementation-dependent) 정의하게 하기 때문에 이런 부분들에 대해서는 전부 각 플랫폼마다의 특성을 따로 반영하여 코딩해주어야 한다.
  • [49] 실제로 요즘 나오는 C 교재중에는 후반부에 OOP 챕터도 넣어놓은 경우가 가끔 있다.
  • [50] 바퀴부터 만든다는것으로 일반적으로는, 이미 다 존재해서 갖다쓰기만 하면 되는것을 괜히 고민하면서 또 만들어내는걸 비판하는데 쓰이는 문구이다.
  • [51] 유닉스의 경우 POSIX API, 윈도우의 경우 Windows API
  • [52] Objective-C 는 C 의 완전한 superset이기때문에 언어 자체로만 보면 사실상 C에 객체지향을 얹은정도의 언어이다.
  • [53] C는 애초에 유닉스 운영체제를 만들기 위해 탄생한 언어이기때문에 유닉스 운영체제와 시스템 궁합이 좋은편이다.
  • [54] 사실, Clang은 OSX 뿐만 아니라, GCC를 대체하는 것이 목표기 때문에 OSX외에 유닉스 계열 운영체제에도 사용된다.
  • [55] 때문에 대부분 언어에서는 if에 bool값이 아닌 int값 등이 들어오면 에러를 내며, 일부 언어에서는 if같이 비교연산이 필요한 곳에서 대입연산을 쓰면 컴파일 에러를 낸다.
  • [56] Python과 그에 영향을 받은 언어들은 이런 영향에서 약간 자유롭다. 이런 언어들은 C와 중괄호가 아닌 들여쓰기로 블럭을 구분하는 특징이 있다.
  • [57] 다만, 현재 객체지향 언어라는 용어는 객체지향을 언어 자체에서 적극적으로 지원해주는 언어들에 쓰인다. C 에는 그런것이 없고, 프로그래머가 OOP 를 원한다면 그것을 위해 따로 정의해서 써줘야 하기때문에 엄격하게 따지면 객체지향 언어라 보기는 힘들다. 또한, OOP 의 몇몇 개념들은 C 에서 정의하기가 상당히 힘들다. 불가능한건 아니지만, 안하는게 생산성에서 더 나을정도로 복잡해진다.
  • [58] 관계가 복잡한데, 볼랜드가 개발언어쪽만 전담하는 코드기어라는 자회사를 설립하면서 모든 권한을 넘겼는데, 코드기어가 엠바카데로사와 합병되면서 이렇게 된 것. 그래서 델파이의 개발도 볼랜드->코드기어->엠바카데로의 순서로 넘어갔다.
  • [59] 프로그래머 포함
  • [60] 비주얼 스튜디오는 어디까지나 C++ 개발도구이다. C++언어 내에서 C를 쓸 수 있기 때문에 묻어가는 것 뿐.
  • [61] 사실은 애플이 GCC를 가져다가 사용하는 대신, 자체적으로 GCC에 추가한 기능 일부를 다시 GCC측에 돌려주기로 약속했었다.
  • [62] 게다가 LLVM은 이것을 처음으로 고안한 사람을 애플이 스카우트하면서 거의 애플 소유의 프로젝트가 되었다. 하지만 스티브 잡스의 애플 복귀 이후 애플이 진행하는 대부분의 소프트웨어 프로젝트가 오픈소스인지라 이것도 역시 오픈 소스로 계속 진행중.오라클 보고있나?