PGR21.com
- 자유 주제로 사용할 수 있는 게시판입니다.
- 토론 게시판의 용도를 겸합니다.
Date 2015/04/18 04:56:45
Name 랜덤여신
Subject [일반] 널 포인터: 10억 달러짜리 실수
소프트웨어 개발을 하시는 분이나, 아니면 일반인(?) 여러분이라도 프로그램이 오류로 종료되었을 때 오류 메시지를 잘 살피신 분이라면, '널 포인터'(null pointer)라는 것을 들어 보신 적이 있을 것입니다.

프로그램을 만들 때, 프로그래머들은 거대한 컴퓨터 메모리를 수많은 조각으로 잘라서 이 조각은 이 용도, 저 조각은 저 용도로 사용하기로 정해 둡니다. 스타크래프트를 예로 들면, 전체 메모리 8기가바이트를 잘개 잘라서, 이쪽 4바이트는 유닛 체력에 쓰고, 저쪽 4바이트는 채취한 광물의 양을 나타내는 데 쓰고, 또 저쪽 8바이트는 유닛의 초당 대미지를 저장하는 데 쓴다는 것이죠.

이때 널 포인터란 '데이터가 아직 없는 상태'를 말합니다. 프로그램을 만들다 보면 여러 가지 이유로 어떤 메모리 공간에 아직 데이터를 저장하지 못할 때가 있습니다. 예를 들어, 아직 유닛이 생산되지도 않았는데 그 유닛의 남은 체력을 저장할 수는 없을 것입니다. 이건 유닛의 체력을 '0'으로 설정하는 것과는 약간 다른 개념입니다. '0'과 '값이 없음'은 의미가 다르죠.

이러한 개념은 엄청나게 널리 쓰이고 있기 때문에, 현존하는 주력 프로그래밍 언어들은 거의 대부분이 널 포인터 또는 그와 유사한 기능을 제공하고 있습니다. C/C++의 널 포인터, 자바의 널 레퍼런스, 파이선의 None, 자바스크립트의 null/undefined, PHP의 NULL 등이 그렇습니다.

----

널 포인터가 야기하는 대표적 문제로 '널 포인터 참조'가 있습니다. 쉽게 말해, 데이터가 아직 없는데 읽으려고 시도했을 때 나타나는 오류입니다. 예를 들어, 적 해병에게 공격을 받아서 유닛 체력을 6만큼 깎아야 하는데, 유닛 체력이 '널'이라면? 이 경우 컴퓨터가 취하는 가장 대표적인 행동은, 그냥 그 프로그램을 꺼 버리는 것입니다.







왜냐하면 널 포인터를 참조하려고 한 그 시점에서 프로그램을 계속 진행하는 것이 의미가 없기 때문입니다. 지금 당장 유닛 체력을 깎아야 하는데, 기존 값이 없기 때문에 계산이 불가능합니다. 이 경우 컴퓨터는 어떻게 해야 할까요? 유닛을 죽여 버린다? 현재 게임만 gg 치고 나간한다? 아니면 게임을 일시 정지한다? 컴퓨터는 이런 것을 판단할 능력이 없기 때문에 (정확히는, 프로그래머가 위기 상황 시 무엇을 해야 하는지 지시를 하지 않았기에) 이러한 오류를 복구 불가능한 것으로 판단합니다. 그래서 '치명적인 오류'입니다.

널 포인터 참조는 보통 프로그래머가 프로그램의 실행 순서를 잘 예측하지 못했기에 나타납니다. 유닛이 생산되기 전에 유닛의 체력을 설정하고 내보냈어야 하는데, 실수로 그냥 내보낸 거죠. 그랬다가 나중에 유닛의 체력이 필요한 상황, 예를 들어 적에게 공격 받거나 해서 체력을 살펴 볼 필요가 있을 때 '펑!' 하고 터지는 것입니다. 이런 종류의 버그는 상당히 흔합니다. 테스트를 아무리 열심히 해도 실수로 빼먹은 경우의 수가 있을 수 있거든요.

----

그런데 널 포인터는 정말로 필수일까요? 널 포인터라는 개념은 '토니 호어'(Tony Hoare)가 1965년에 처음 발명했습니다. 그리고 40년이 흐른 2009년, 토니 호어는 한 강연에서 다음과 같이 말했습니다:


(널 포인터는) 내 10억 달러짜리 실수였다. 1965년 당시, 나는 ALGOL W라는 객체 지향 언어에 쓰기 위해 포괄적인 타입 시스템을 설계하고 있었다. 내 원래 목표는 어떤 데이터를 읽든 항상 안전하도록 컴파일러가 자동으로 확인해 주는 것이었다. 그러나 나는 널 포인터를 집어넣으려는 유혹을 이길 수가 없었다. 그렇게 하는 게 훨씬 쉬웠기 때문이다. 이 결정은 셀 수도 없는 오류와 보안 버그, 시스템 다운을 낳았다. 지난 40년 동안 이러한 문제들 때문에 입은 고통과 손해는 10억 달러는 될 것이다.


그렇다면 대안은 무엇일까요? 여기서부터 좀 어려워지는데요. 이제부터는 개발자-언어를 사용할 것이기 때문입니다.

오늘날 가장 유명하고 가장 널리 쓰이는 대안은 'sum type' 또는 'tagged union'이라고 불리는 개념입니다. 개발자-언어로 옮기면, '널이 될 수 있는 변수는 따로 분류하자'는 것이죠. (원래는 약간 더 복잡하고, 약간 더 유용한 기능입니다. 자세한 것은 다음 기회에!)

예를 들어 설명하면 이런 느낌입니다.


Animal dog = new Animal(); // dog은 '일반 포인터'입니다. 일반 포인터는 항상 값을 가리키고 있으며, 절대로 널이 되지 않습니다.

Animal? cat = null; // cat은 '널이 될 수 있는(nullable) 포인터'입니다. 일단 null로 초기화해 봅시다.


일반적인 포인터과 달리, 널이 될 수 있는 포인터들은 사용하기 전에 명시적으로 '허락'을 받아야 합니다. 대표적으로 if를 사용할 수 있겠죠.


print(dog.name) // dog은 절대로 널이 되지 않는다는 것이 보장되어 있으므로 마음껏 사용해도 됩니다!

// 한편, cat은 널이 될 수 있는 포인터이므로 사용하기 전에 반드시 if를 넣어서 null 여부를 확인해야 합니다. 만일 이를 어기면, 컴파일 단계에서 컴파일러가 오류를 낼 것입니다.
if (cat == null) {
    print('무언가 잘못되었다. 난 여기서 빠져 나가야겠어.');
} else {
    print(cat.name);
}


특정 포인터들만 널이 될 수 있게 하고, 그러한 포인터는 사용하기 전에 항상 널 여부를 확인하게 함으로써, 모든 널 포인터 참조 오류를 없애버릴 수 있습니다. 또한 대부분의 포인터는 널이 아니라는 것이 보장되어 있기 때문에 마음 편히 쓸 수 있습니다. 요즘 나오는 언어들은 대부분 이 기능이 기본 탑재되어 있고, 기존 언어들도 하위 호환성 때문에 널 포인터를 완전히 없애지는 못하지만 이 기능과 유사한 개념을 탑재하기 시작하고 있습니다.

스위프트, 러스트, 하스켈, 스칼라, 코틀린 등이 sum type을 가지고 있는 대표적인 언어입니다. 이러한 언어에서는 널 포인터를 사전에 컴파일러가 차단하므로 널 포인터 오류가 나지 않습니다. 자바스크립트에서도 http://flowtype.org/ 라는 것을 사용하면 완전히는 아니더라도 사전에 널 포인터를 예방할 수 있습니다.

과연 이러한 언어들이 흥해서 10억 달러짜리 실수를 다소나마 만회할 수 있을지 기대됩니다.

통합규정 1.3 이용안내 인용

"Pgr은 '명문화된 삭제규정'이 반드시 필요하지 않은 분을 환영합니다.
법 없이도 사는 사람, 남에게 상처를 주지 않으면서 같이 이야기 나눌 수 있는 분이면 좋겠습니다."
Cazellnu
15/04/18 06:15
수정 아이콘
장, 단점이 명확하다고 봅니다.
대형화될 수록 오류가 발생하지 않을 확률이 거의 없다고 봐야겠지만
그만큼 개발자가 입맛에 맛게, 가지고 놀고 싶은데로 쓰일 수 있다는 장점이 있겠지요.
개인적으로는 후자쪽을 더 중시합니다.
랜덤여신
15/04/18 06:21
수정 아이콘
'입맛에 맞게 쓸 수 있다'라면 표현력을 말하는 것일 텐데, 이 점에 있어서는 sum type쪽이 오히려 낫습니다. 단적인 예로, sum type이 있는 언어에서는 모든 포인터를 nullable로 설정함으로서 전통적인 포인터를 흉내낼 수 있지만, 그 반대는 불가능합니다.

다르게 생각하면, 기존 언어들은 '모든 포인터가 처음부터 강제로 nullable인 상태'라고 말할 수 있겠죠. 당연히 nullable을 제거할 수 있는 sum type 쪽이 더 입맛에 맞게 쓸 수 있습니다.
Cazellnu
15/04/18 06:33
수정 아이콘
정해서 놓고 쓰는것이 아닌 쓰고싶은 타입으로 캐스팅하고 다니며 이를 이용해 많은 짓을 할 수 있다는것이죠.
나머지는 개인적인 생각인데 널을 제거 할 이유를 사실 납득을 못하는 것도 있네요
만약 널 참조오류가 발생했던 상태라면 거기에서 참조오류만 발생하지 않았다뿐이지 개발자가 의도하지 않았던 곳으로 포인팅을 하게 되는 경우가 태반이라 역시나 오류라는 점에서는 다를게 없다는게 제 생각이네요.
랜덤여신
15/04/18 06:43
수정 아이콘
뭔가 프로그래밍 언어 꼰대(?)처럼 들리는 것 같기도 하지만... 직접 써 보시면 장점을 더 확실하게 느끼실 수 있을 거라고 생각합니다. 저도 sum type이 있는 언어들을 쓰기 전에는 '널처럼 유용한 걸 왜 없애야 하나...'라고 생각했습니다. 그런데 막상 써 보니 너무 편하더군요.

정말로, 저도 써 보기 전에는 널 포인터처럼 필수적인 것을 어떻게 없앨 수 있는지 무척 회의적이었습니다. 그런데 됩니다. 진짜 됩니다. 캐스팅 같은 것도 전혀 문제 없습니다!
15/04/18 13:28
수정 아이콘
개발비용 단축이라는 측면으로 보면 굉장히 큰거죠.
크게 고려해야 할 사항 중 하나를 고려하지 않아도 되니까요.
즐겁게삽시다
15/04/18 08:51
수정 아이콘
흐흐흐 재밌게 잘 읽었습니다.
자바스크립트 처음 배울 때 이것 땜에 진짜 어렵더군요;;; 오류는 나는데 뭐가 오류인지 못찾겠고 한참 보다보면 null값 때문이고;;;
김연우
15/04/18 09:12
수정 아이콘
이게 sum type이랑 비슷한건진 모르겠는데, 전 static으로 Null Variable을 선언해서 씁니다.

그럼 가령
if (var) {
printf("%s", var->name);
}
이렇게 안하고
printf("%s", var->name);
만 해도, var가 null대신 전역 변수인 Null Variable이라면 name에 "NULL" 문자열을 넣어주면 그만이니까요.

디버깅 정책/관점의 차이에 따라 쓸모 없을 수도 있는데, 잘만 사용하면 많은 경우 효율적이니까요.
랜덤여신
15/04/18 11:06
수정 아이콘
재밌는 아이디어군요. sum type이랑 비슷해 보입니다. 값이 없다는 상태도 값으로 나타내는 거니까요.

하지만 의미상으로는 어떻게 되는 건지 좀 갸우뚱하군요. sum type은 널일 경우 아예 못 쓰게 하지만, 말씀하신 방법에서는 기본값 변수(?)가 대신 사용되겠군요. 유닛 체력을 다시 예로 들면 널이 될 상황이 발생할 때마다 기본값 변수의 유닛 체력이 대신 깎인다는 것인데... 음. 프로그램이 죽는 것보다는 낫다고 생각할 수도 있지만 저는 프로그래머의 초기 의도와 달라졌다는 생각이 먼저 듭니다.
15/04/18 11:57
수정 아이콘
var 포인터 캐스팅 워닝뜰거 같은데..
2막4장
15/04/18 09:51
수정 아이콘
크크 이런 거 재미있어요.
MFC랑 C/C++만 하다가 C#을 요새 좀 하고 있는데, new는 있어도 delete는 자동으로 해준다는 개념이 참 생소하면서 편리하더군요..
맨날 메모리 새는거 땜에 설비 담당자랑 싸우고 그랬는데... 지금은 딱히 고민할 필요가...(하지만 이제 메모리가 기본 8GB는 되서 C++이라도 덜 고민되는 건 함정..)
15/04/18 15:44
수정 아이콘
가비지 콜렉션 때문에 가능한건데요...
C++ 쪽에서도 최근에 나온 STL 진영에서는 auto_ptr, shared_ptr 등으로 흉내낼 수 있지요.
그리고 솔직히.. 가비지 콜렉션 자체가 생각보다 완벽하지 못해서, C#도 메모리 샙니다.. 쓰다보면... 흐흐...
2막4장
15/04/18 17:42
수정 아이콘
크크 그렇군요~ 누수의 원인을 랭귀지로 돌릴수 있으니 것도 괜찮습니다
근데 이렇게나 편리한 언어들이 많이 등장하는데 C++의 생명은 언제까지 유지가 될까요? 여전히 플랫폼적응이나 스피드에서 강점을 보이는 걸까 싶네요
15/04/19 01:19
수정 아이콘
지금도, 어플리케이션을 개발할때는 자바스크립트, 자바, C#, 파이선...
그 외에도 Go, 러스트, 헤스켈 등등의 신생(?) 언어들이 많이 쓰이는 추세지만,
코어 라이브러리를 제작할 때는 어쩔 수 없이 C/C++로 제작하게 되더라고요.
게다가, 4세대 언어들이 할 수 없는 극단적인 최적화는 C/C++의 최대 강점이라서...
제 개인적인 생각으로는, 파스칼을 더 이상 안쓰게 된 지금은, C/C++은 끝까지 갈 것 같아요.
게다가, 최근 나오는 언어들도 문법의 기반은 죄다 C/C++에 있다는 것도 한 몫 하고요.
유리한
15/04/18 10:38
수정 아이콘
c 계열 언어의 문제는 널포인터보다 댕글링 포인터가 역시..
랜덤여신
15/04/18 11:13
수정 아이콘
확실히 그렇습니다만, 저는 파이선을 오래 해서, 댕글링 포인터의 괴로움은 상대적으로 덜 겪었습니다. 그리고 파이선의 None은 이름만 다를 뿐 널 포인터랑 다른 게 없지요.

댕글링 포인터에서 해방됐는데도 불만이 드는 걸 보니, 사람 욕심이 끝이 없는 것 같습니다. 하하
15/04/18 15:46
수정 아이콘
글쵸, 솔직히 널포인터는 어떤식으로는 우회할 방법이 있고, 최근에 나온 실행전 코드분석툴 등에서 잡아주기도 하니까요.
댕글링 포인터가 제일 짜증나죠. 특히나 멀티스레드 방식으로 만들다보면... 아오...
세계구조
15/04/18 11:32
수정 아이콘
언어 초보가 러스트를 배우려는데 참고할 수 있는 서적이 아직 없겠죠? 개발환경 설정부터 설명되어 있으면 좋은데.
15/04/18 12:00
수정 아이콘
현 시점에는 공식 홉페이지의 서적이 가장 낫습니다. 아직은 베타라 이 물건마저도 완전히 최신 상태를 반영한건 아니지만 대부분의 주제에 대해서는 별 문제 없이 공부하실 수 있을겁니다.

http://doc.rust-lang.org/book/
세계구조
15/04/18 12:07
수정 아이콘
고맙습니다!
15/04/18 12:02
수정 아이콘
요즘들어 파이썬만 보다보니까 C언어가 무슨 어셈블리만큼이나 로우레벨로 보이기 시작했습니다.
15/04/18 12:15
수정 아이콘
여담이지만 여지까지 널 포인터를 가지고 나온 대부분의 정적 타입 언어의 개발자들이 한 입을 모아 말하는 내용 중 하나가 "널 포인터의 도입은 실수"라는 겁니다. 동적 타입 언어야 이걸 체크할 도리가 없으니 어쩔 수 없다지만요. C++은 레퍼런스를 도입했고, C#은 "여러분들이 언어를 만들면 널 포인터를 넣지 마세요!"라고 조언하고, 자바는 나중 가서야 NonNull 어노테이션을 추가하고...

어쨌든간에 기계적으로 체크할 수 있는 문제점을 사람이 체크하게 하도록 만들면 나중에 가서 후회를 하게 되죠. 이런 중요하지 않은 문제는 전부 기계가 체크하도록 하는게 좋습니다.
유리한
15/04/18 13:08
수정 아이콘
여담으로 obj-c 는 널포인터에게 메세지를 날리면 쌩까도록 설계가 되어있습니다. 크크
대신 문제는 댕글링포인터..
15/04/18 15:49
수정 아이콘
그러니까, 둘 다 문제없는 C#을 씁시다! (응?)
최근 xamarin에 기대를 거는 중입니다. 멀티플랫폼 프로젝트를 하겠다고 언어를 여러가지를 쓰는건 너무 낭비같아요. ㅠㅠ
YORDLE ONE
15/04/18 15:22
수정 아이콘
항상 좋은글 감사합니다
깡디드
15/04/26 08:55
수정 아이콘
항상 재밌는 글 감사합니다
목록 삭게로! 맨위로
번호 제목 이름 날짜 조회 추천
공지 [일반] [공지]2024년 4월 총선을 앞두고 선거게시판을 오픈합니다 → 오픈완료 [53] jjohny=쿠마 24/03/09 29177 6
공지 [정치] [공지] 정치카테고리 운영 규칙을 변경합니다. [허들 적용 완료] [126] 오호 20/12/30 250620 0
공지 [일반] 자유게시판 글 작성시의 표현 사용에 대해 다시 공지드립니다. [16] empty 19/02/25 326692 8
공지 [일반] [필독] 성인 정보를 포함하는 글에 대한 공지입니다 [51] OrBef 16/05/03 449629 28
공지 [일반] 통합 규정(2019.11.8. 개정) [2] jjohny=쿠마 19/11/08 320011 3
101410 [일반] [팝송] 맥스 새 앨범 "LOVE IN STEREO" 김치찌개48 24/05/06 48 0
101408 [일반] 장안의 화제(?) ILLIT의 'Magnetic'을 촬영해 보았습니다. [11] 메존일각1654 24/05/05 1654 8
101407 [일반] [글쓰기] 아니 나사가 왜 남아? [6] 한국외대1875 24/05/05 1875 2
101406 [일반] [만화 추천]그리고 또 그리고...잡담 ​ [6] 그때가언제라도1758 24/05/05 1758 2
101405 [일반] 시흥의 열두 딸들 - 아낌없이 주는 시흥의 역사 (11) 계층방정828 24/05/05 828 5
101404 [일반] 신난다 어린이 날, 즐겁다 어린이 날 [6] 착한아이2697 24/05/05 2697 8
101403 [일반] (락/메탈) Silverchair - Without You (보컬 커버) [5] Neuromancer1459 24/05/05 1459 1
101402 [일반] <스턴트맨> - 우린 그럼에도 액션영화를 만든다.(노스포) [6] aDayInTheLife2337 24/05/05 2337 3
101401 [일반] [팝송] 피더 엘리아스 새 앨범 "Youth & Family" 김치찌개1283 24/05/05 1283 0
101400 [일반] 예전 닷컴버블때와는 달리 지금은 AI버블이 일어나기 힘든 이유 [31] 보리야밥먹자8747 24/05/04 8747 3
101399 [일반] 시흥의 열두 딸들 - 아낌없이 주는 시흥의 역사 (10) [4] 계층방정2830 24/05/04 2830 3
101398 [일반] (미국주식)간략하게 보는 2분기 유동성 방향 [16] 기다리다3889 24/05/04 3889 0
101397 [일반] 못생겨서 그렇지 제기준 데일리 러닝용으로 최고의 러닝화.JPG [18] 2023 lck 스프링 결승 예측자insane5318 24/05/04 5318 1
101396 [정치] 채수근 상병 순직 특검법 21대 회기 중 본회의 통과 [59] 사브리자나3841 24/05/04 3841 0
101394 [일반] 최근 내 삶을 바꾼 제품들 총 6선 - 전구, AI에서 태블릿 pc까지 [31] Kaestro4510 24/05/04 4510 7
101381 댓글잠금 [일반] [후원] 유니세프 페이커 패키지 기부 동참 이벤트 [1] 及時雨4705 24/05/01 4705 0
101392 [일반] 수학은 커녕 산수도 헷갈리는 나, 정상인가요? [66] 만렙법사7222 24/05/03 7222 4
101391 [일반] 가정의 달 5월이네요 [8] 피알엘5554 24/05/03 5554 4
목록 이전 다음
댓글

+ : 최근 1시간내에 달린 댓글
+ : 최근 2시간내에 달린 댓글
맨 위로