안전성이란 관점에서 C 언어를 어떻게 작성할지에 대해
이야기하겠습니다. 그리고
일반적인 개념으로, 안전성이란 무엇일까요?
어떤 종류의 안전성이 있고 우리에게 무엇이 필요할까요?
이것이 첫 번째 부분입니다. 그 다음으로 우리가
수십 년간 이를 조금씩 다루어왔다는 것을 보여드리겠습니다.
이는 C 언어의 초기 목표의 일부였습니다.
그 다음 C 핵심 가이드라인이라는 이름 아래 현대적인 C를
어떻게 잘 작성할 수 있는지 이야기하겠습니다. 그리고
프로파일에 대해 이야기하겠는데, 이는 안전성을
보장하는 방법에 관한 것입니다. 가이드라인과
주의를 기울이는 것만으로는 모든 영역에서 충분하지 않기 때문입니다.
안전성에 대한 논의가 많은 이유 중 하나는
미국 정부의 일부가 안전성에 대해
언급하기 시작했기 때문입니다. 이는 꽤 합리적이지만,
그들은 전체 커뮤니티에 대해 이야기하고 있습니다.
이것이 사실일 수도 아닐 수도 있죠. 그리고 그들은 신화적인
C/C++ 언어에 대해 이야기하고 있는데, 이에 대해
제가 할 말이 있습니다. 어쨌든 찾아보실 수 있습니다.
이는 우리가 다뤄야 할 심각한 문제입니다.
반면에, 당황할 이유는 없습니다.
C는 일반적으로 잘 하고 있습니다.
제 말은, TIOBE는 사용량이 아닌 소음을 측정합니다.
그래서 이 숫자들은 정확히 아무것도 보여주지 않지만,
하지만 이는 아마도
10억 또는 20억 명의 사람들이 우리가 하는 일에 의존하고 있음을 보여줍니다. 그래서 우리는
더 잘해야 합니다.
따라서 우리는 안전성 문제를
해결해야 합니다. 이는 정말 심각한 문제입니다. 제 말은,
제가 차를 가지고 있다면 브레이크를 밟았을 때 작동하지 않는 걸
정말 원치 않습니다. 그리고 다른
문제들도 있습니다. 금융업에 종사한다면,
거래가 사라지는 걸
원치 않을 겁니다. 특히 그 거래가 당신의 계좌로
들어오는 거래였다면 말이죠. 그래서 이에 대한
많은 측면이 있습니다. 그리고
흥미로운 점은 많은 영역에서 정말 대규모 개선이
가능하다는 것입니다. 이 강연에서 제가 전하고 싶은
메시지 중 하나는, c나 C를 쓰지 말고
C를 쓰라는 것입니다.
우리는 문서화된 몇몇 문제들보다 훨씬 더 잘할 수 있습니다.
그리고,
우리가 하지 않으면 다른 누군가가 우리에게 뭘 하라고 말할 거예요.
그리고 우리는 그걸 더 싫어합니다.
안전 문제를 무시하면 커뮤니티에 해가 될 것이고,
보장된 안전을 제공하는 것은 C의 가장 좋은 전통이
될 것입니다. 이것은 실제로 기회입니다. 즉,
문제가 있다고 해서 좋은 일을 하지 못하게 하지 마세요.
그래서 완전한 타입과 리소스 안전성이라는
아이디어는 C에서 처음부터 있었습니다. Simula는
완전히 안전한 언어 중
하나였습니다,
버그만 제외하면요. 저는 그걸 깨는 데 꽤 능숙했죠.
하지만 우리가 아는 한 가지는
당시 우리가 가진 하드웨어로는 완전한 안전을 할 수 없었고
지금도 모든 언어와 모든 용도에 대해
할 수 없다는 겁니다. 하지만 조심한다고 해서 겁먹을 필요는 없죠.
그래서 우리는 신중한 프로그래밍 기법을 사용해야 합니다.
라이브러리가 지원하고, 언어 규칙과 분석으로 강제되는
기법 말이죠. 그래서 저는 몇 년 전에
이를 수행하는 기본 모델을 작성했습니다. 실제로
여기서 발표도 했지만, 별로 진전은 없었죠.
우리는 그것이 C가 되길 원합니다. 즉, 우리가 할 수 있는 것에
제한이 없어야 합니다.
구현 방식에 제한이 있을 수 있지만,
성능 저하는 없어야 합니다.
이것이 C언어이며, 실제로 안전한 코드를 작성하는
일부 기술은 성능을 향상시킵니다.
주로 컴파일러와 정적 검사로 할 수 있는 것에 대해 말하고 있습니다.
이는 무료이거나 실제로 성능을 개선시키기 때문입니다.
하지만 정적으로 처리할 수 없는 것들을 다루기 위해
범위 검사가 필요합니다. 그래서 기본적으로
타입과 리소스 안전성에 대해 이야기하고 있습니다.
이는 잘 정의되어 있다고 생각합니다.
모든 객체는 정의된 타입에 따라 접근됩니다.
이것이 타입 안전성입니다. 그리고 모든 객체는 적절히
생성되고 소멸됩니다. 이것이 리소스 안전성입니다.
이렇게 리소스를 관리할 수 있습니다.
초기화하지 않으면 규칙을 위반하는 것입니다.
모든 포인터는 유효한 객체를 가리키거나 널 포인터입니다.
이것이 메모리 안전성입니다. 이는 달성하기 더 어렵지만
가능합니다. 그리고 포인터를 통한 참조는
널 포인터를 통하지 않습니다. 즉, 역참조하기 전에
널 포인터를 확인해야 하고, 유효한 포인터를 역참조하며,
접근해야 합니다.
그리고 포인터를 통한 접근은
서브스크립트 포인터는 런타임 검사가 필요한
범위에 있습니다. 이에 대해 곧 설명하겠습니다.
기본적으로 이는 규칙이 요구하는 바입니다.
표준을 읽으면 그것이 요구하는 것이
바로 이것입니다. 데니스 리치의
78년 45페이지 C 매뉴얼을 읽어보세요.
그것이 요구하는 바입니다. 우리가 지금까지
그렇게 하지 않았을 뿐입니다. 제가 여기서 제시하는
규칙들은 발명보다는 추론된 것입니다.
이 슬라이드에 있는 내용을 수행하는 데 필요한 것을 추론한 것입니다.
제가 제안하는 시행 규칙들은
상호 의존적입니다. 맥락을 무시하고 한 가지만 뽑아내서
쉽게 명시된 이점을 얻을 수는 없습니다.
무엇을 하고 있는지에 대한 프레임워크가 있어야
그로부터 무엇을 얻으려 하는지 알 수 있습니다.
그리고 C는 여전히
다양한 사용자와 영역을 위해 존재해야 합니다.
수백만 명의 사용자와 수십억 명이 우리에게 의존하고 있으며,
한 가지 방식이 모두에게 맞지는 않습니다.
우리는 단순히 "이것이 안전이다.
모두가 이렇게 하라"고 말할 수 없습니다.
그것은 작동하지 않습니다.
작동하지 않습니다. C는 또한 시스템 프로그래밍 언어입니다.
우리는 다양한 방식으로 하드웨어를 조작합니다.
언어 사양에 알려지지 않은 특이한 하드웨어를 사용하며,
이를 다른 언어에 아웃소싱할 수 없습니다. 많은
소위 안전한 언어들은 모든 저수준 작업을
C에 아웃소싱합니다. 그래서 만약
우리가 그것을 잘 할 수 없다면, C만 남게 될 것입니다.
기본적으로. 하지만 누군가는 이 더러운 일을 해야 합니다.
그리고 우리는 수십억 줄의 기존 코드를 깨뜨릴 수 없습니다.
할 수 없다고 말하지, 하지 말아야 한다고 하지 않습니다. 우리가 시도하면,
사람들은 구 컴파일러를 사용하거나, 다른 서브셋으로 가거나,
우리를 무시할 것입니다. 이는 불가능합니다.
그리고 우리는 수백만 명의 개발자를 빠르게 업그레이드할 수 없습니다.
시간이 오래 걸립니다. 나는 10년이나 20년 된
비디오와 책으로 C를 배운 사람들을 계속 만납니다.
비극적이지만, 최신 자료로 배웠다면
훨씬 더 쉽고 결과가 더 좋았을 것입니다.
최신 자료로 가르치는 것은
중요합니다. 하지만 이런 전체 커뮤니티를
앞으로 나아가게 하는 것은
훨씬 더 어렵습니다.
대부분의 사람들이 상상하는 것보다 더 어렵습니다. 이러한
어려움이 있지만, 우리는 개선해야 하고
할 수 있습니다. 그래서 과제는
타입 안전한 C 사용이 무엇을 의미하는지 설명하는 것입니다.
정적 타입 시스템 위반 없음, 리소스 누수 없음.
시스템이 리소스를 누출한다면,
메모리 잠금, 파일 핸들 등과
같은 것들이요, 저는 그것을 안전하다고 보지 않습니다. 서비스 거부 공격과
유사한 방식으로 시스템을 충돌시킬 수 있기 때문입니다.
아니면 그냥 부주의해서 리소스가 소진되면 충돌할 수도 있죠. 그래서 저는
리소스 안전성에 매우 관심이 많습니다. 이것은 실제로
C++에 처음 두 주 동안 도입된
것 중 하나이며, 우리는 개발자들이 이를 수행하도록
설득해야 합니다. 지저분하고 복잡한 저수준 작업을 하면
반드시 더 빠를 거라는 믿음이 많이 있습니다.
게다가,
이런 지저분하고 저수준의 복잡한 코드를 작성해서
내가 얼마나 똑똑한지 보여줄 수 있다고 생각합니다.
하지만 이는 통하지 않습니다.
작동하지 않습니다.
우리는 프로그래밍 수준을 높이고
이것이 규모에 맞게 작동하도록 해야 합니다. 제가 학생들을 가르친다면,
내가 시키는 대로 하게 할 수 있는 이유는 그렇지 않으면 그들이 나쁜
성적을 받기 때문입니다. 관리자라면 당신이 원하는 방식으로
코드를 작성하게 할 수 있습니다. 그렇지 않으면 그들은 승진을 못하거나
해고됩니다. 하지만 규모가 커지면,
우리는 실제로 사람들을 설득해야 합니다. 그들이 그것이 사실이라고 믿어야 합니다.
그래서 그것이 중요합니다. 그리고 수십 년에 걸친
안정성이 중요합니다. 사람들이 오늘 작성한 코드가 10년 후에도
실행될 것이라고 믿는 유일한 이유는
10년 전에 작성된 코드가 오늘날 실행되기 때문입니다. 그리고 안전성은
단순히 타입 안전성만이 아닙니다.
타입 안전성만이 아닙니다.
제가 보는 대부분의 영역은 논리적 오류입니다.
더 큰 것이 예상되는 곳에
작거나 같은 것을 본 적이 있고
그 비용은 매우 컸습니다.
그리고 만약 프로그램이 정확히
무엇을 하는지 증명하고 싶다면 매우 제한된 언어를 얻게 됩니다.
그 방향으로 가는 일부 Ada 코드가 있습니다.
리소스 누수. 제가 언급한 동시성 오류들.
우리는 문제를 확장하기 위해 많은 동시성을 사용하고 있습니다.
우리는 문제를 확장하기 위해 많은 동시성을 사용하고 있고,
이것이 안전한지 확실히 해야 합니다.
작동합니다. 동시성 오류를 고려할 수 있습니다
객체가 올바르게 사용되지 않았기 때문에 일어나는 유형 위반이지만,
이를 분리하여 직접 분석하고 해결할 수 있도록 하는 것이 매우 중요합니다.
메모리 손상, 우리는 이것을 반드시 제거해야 합니다
유형 오류. 만약 저수준 코드를 사용하면서
많은 캐스팅과 void 포인터를 사용한다면
그리고 다른 까다로운 것들처럼,
void는 더 나쁩니다. 우리는
이를 피해야 하며 타이밍 오류도 마찬가지입니다. 만약
응답이 예를 들어 1.2밀리초 내에
필요하다면, 그렇지 않은 경우는
시간을 맞추지 못한 것입니다.
제시간에 맞추지 못하면, 많은 실시간 제어
애플리케이션에서는 충분하지 않습니다
그리고 할당의 예측 불가능성. 비행 소프트웨어에서는
자유 저장소 사용에 대한 금지가 있습니다.
엔진이 시작된 후에는 무언가를 할당할 수 없고,
어느 시점에서도 할당 해제를 할 수 없습니다. 왜냐하면
단편화와 같은 문제가 발생할 수 있기 때문입니다.
이는 별도로 관리되는 메모리 청크가
C에서 매우 중요하다는 것을 의미합니다. 모든 중요한 애플리케이션에서
이는 필수적입니다.
옆에서 자체적으로 메모리를 관리하는 무언가를 가지고 있습니다.
벡터가 첫 번째이자 가장 간단한 예시입니다. 우리 모두가
사용하고 있죠. 실제로 메모리 덩어리를 가져와서
관리해 줍니다. 그리고 종료 오류가 있습니다.
저는 종료가 허용되지 않는 시스템을
다뤄봤습니다. 예를 들어 40,000개의 프로세서가 있다면,
대략 매일, 또는 최소 매주 무언가가
충돌할 것이라는 점을 고려해야 합니다. 따라서
프로세서에 문제가 있으면 그냥 충돌시키는
전략을 가질 수 있습니다. 우리가 소프트웨어를 그렇게 작동하도록
작성했기 때문이죠. 하지만 그런 여분이 없다면 어떨까요?
충돌이 허용되지 않는다면 어떨까요?
제 친구는 스쿠버 다이빙 컨트롤러를
프로그래밍하고 있다고 지적했습니다. 거기엔 프로세서가 하나뿐입니다.
아니요, 충돌은 선택사항이 아닙니다. 일부 금융 시스템에서는
법적으로 충돌할 수 없습니다. 거래를 잃게 되고,
그것은 법적으로 허용되지 않기 때문입니다.
여기에는 많은 것들이 있습니다. 여러분도
이런 종류의 예시를 다른 슬라이드나
반 슬라이드 정도 더 찾을 수 있을 겁니다. 우리는
우리가 무엇을 하려는지 말할 수 있어야 합니다. 모든 곳에서 모든 것을
하려고 하지는 않습니다. 그것은 필요하지 않기 때문입니다.
많은 사람들이요. 그리고 어쨌든 우리가 말하는 규모에서는
실현 가능하지 않습니다. 그래서 보안은
메모리 안전성이 아닙니다. 보안과 안전성 사이에
약간의 혼동이 있었습니다.
타입 안전성. 타입 안전성은 보안이 아닙니다.
오래 전 벨 연구소에서 보안 과정을
수강한 적이 있습니다.
첫 번째 수업은 자물쇠 따기였습니다.
두 번째 수업에서는 건물에 들어갈 때
배지를 사용할 수 없었습니다. 제가 당신의 컴퓨터,
모든 백업 테이프, 모든 메모리 스틱을 얻을 수 있다면
당신의 정보를 모두 얻게 됩니다.
내부자 공격이 있습니다. 만약
당신이 큰 조직이라면, 매수당하거나
회사의 이익과 다른 이상을 가진
자유로운 사람들이 있습니다. 스피어 피싱이
매우 효과적이라고 합니다. 문을 흔들어보면
충분히 많은 곳을 시도하면 사람들이 제대로 하지 않은 곳이 있습니다.
서비스 거부, SQL 인젝션,
손상된 입력 데이터. 그래서
무언가를 공격하고 싶다면 항상 가장 약한 고리를 공격합니다.
뉴하트에서 차량 도난을 피하는 방법을 들었는데
공항? 정답은 더 좋은 차 옆에 주차하는 것입니다.
차.
제가 지적하는 것은 타입 안전성과 메모리 안전성,
그리고 그와 같은 것들에 대해 말하고 있습니다. 하지만 이를
보안과 혼동하지 마세요. 보안은 시스템 속성입니다.
그리고 시스템에는 컴퓨터, 사람,
저장 영역, 물리적 요소, 많은 것들이 포함됩니다.
저는 그 모든 것을 말하는 것이 아닙니다. 하지만 누군가가 와서
프로그램에 버그가 있을 수 있다고 보안을 외치면 기억하세요.
언어는 안전하지 않습니다.
보다 작음 기호를 보다 큼 기호 대신
쓰는 것과 같은 일 말입니다. 모든 안전한 범용
언어에는 예외 조항이 있습니다. 하드웨어 리소스에 접근해야 하고,
주요 추상화의 효율성을 개선해야 합니다.
안전한 연결 리스트 구현을 하는 것은
검증된 안전성을 원한다면 매우 매우 어렵습니다.
우리가 정지 문제에 직면해 있다고 생각하지만,
그냥 거의 불가능하다고 말하겠습니다.
그래서 우리가 하고 싶은 일들이 있고
검증 가능한 안전성이 아닌 기술을
사용해야 합니다. 그리고 신뢰할 수 있는
코드 세그먼트가 작동합니다. 그것들이 문제입니다.
물론 스팟도 있지만, 덜 엄격한 규칙으로 작성된 라이브러리 코드도 있습니다.
뭔가를 호출해야 합니다.
C로 작성된 운영 체제는 어떨까요?
그런 이유로 운영 체제를 검증할 수 없습니다.
너무 복잡하죠. 그리고 종종
예외 조항은 C입니다. 그래서 우리는
모든 안전하지 않은 영역을 닫을 수 없습니다.
중요한 곳에서 안전하고, 중요한 곳에서 보장되며,
가능하면 기본적으로 그렇게 하는 것이
정말 좋습니다. 따라서 절대적인 안전을 얻을 수 없다고
지적하는 것은 안전 문제를 무시하는 변명이 될 수 없습니다.
오히려 우리의 노력을 실제로 진전을 이룰 수 있는
곳에 집중해야 한다는 주장입니다.
그래서 저는 역사를 거슬러 올라가보겠습니다.
제가 C로 시작한 이유 중 하나는
하드웨어를 다루고 싶었고 그것을 추상화해서
더 나은 코드를 작성하고 싶었기 때문입니다. 정적 타입
안전성이 그 아이디어였죠. 저는 한동안 정적으로 안전한
언어로 글을 쓰고 코딩을 해왔습니다.
여기에는 C의 고수준 기능의
뿌리가 되는 시뮬라도
포함됩니다. 우리는 클래스가 있었고,
캡슐화 같은 것들입니다.
하지만 이는 달성하기 어려운 이상입니다.
때로는 진전이 필요하고, 때로는 더 나은
우리의 이해에 대한 진전이 필요합니다. 때로는 더 나은
하드웨어가 필요합니다. 그래서 하드웨어의
효율적인 사용, 그것이 C의 영역이고,
복잡성 관리, 그것이 Simula의 영역입니다. 그리고 저는
우리가 할 수 있고 여유가 있는 곳에서 더 Simula 쪽으로
우리를 옮기려고 노력해왔습니다.
자, 제가 시작했을 때,
제곱근을 호출하고 싶다면,
기계가 충돌할 수 있었습니다. 운이 좋다면 2의 제곱근이 기계를 충돌시켰습니다.
그렇지 않으면 그냥 잘못된 결과를 줬습니다.
문제는 컴파일러가 double이 필요하다는 것을 잊었고
변환되지 않았다는 점이었습니다.
그래서 제가 처음으로 한 일 중 하나는
그런 것들이 충돌하지 않도록 하는 것이었습니다. 충돌은
안전 문제로 간주되기 때문입니다. 저는 이것을 바로 시작했다고 말할 수 있습니다.
사실,
언어를 강화하는 맥락에서 매우 흥미로웠습니다.
그 작은 수정으로 10년 동안 문제가
있었습니다. 제 말은,
오늘날의 C도 그렇습니다. 하지만 당시에는 논란의 여지가 있었죠.
의미를 알려면 선언을 봐야 한다는 말인가요?
코드만 봐서는 안 된다고요. 그런 주장을 많이 들었습니다.
호환되지 않는다는 거죠. 초기에 사람들이 C++을
좋아하지 않을 때마다 지적했던 게
바로 호환성 문제였습니다.
다르다, 제대로 일을 하지 않았다고 말이죠.
하지만 호환성을 포기하지 않고서는
타입 안전성을 얻을 수 없었습니다. 그리고 제가 깨달은 건, 사람들이
C++ 같은 언어를 쓰기 싫을 때,
뭔가를 골라서 "아, 이건 오늘날 그렇게 하지 않아"
라고 말한다는 겁니다. 안전성이요. 안전하지 않다고요.
어쨌든 그건 필수적이었습니다. 타입
검사, 오버로딩, 사용자 정의 타입,
일관된 링킹, 타입 안전 링킹, 이 모든 것들은
언어가 인자 검사를 제대로 지원할 것을
요구합니다. 좋습니다. 때로는 그냥 해야 할 때가 있죠.
중요한 일이니까요. 그리고 안전성 문제에 대해
다시 다룰 것 같습니다. 기본 아이디어는 코드로
사물을 표현하고 사용할 수 있는 추상화를
만드는 것이었습니다. 그러면 코드가 더 간단해지고
실제로 더 안전해집니다. 벡터, 문자열, 파일 핸들
동시 작업 메시지 큐. 이런 식으로 계속됩니다.
안타깝게도 오늘날 모두 표준화되지는 않았지만,
대부분은 그렇습니다. 시간이 걸리는 일이죠.
안전성을 다루려면 그 개념을 지원하는
추상화가 필요하다고 생각합니다.
불변성은 초기에 도입되었습니다.
const가
필요하다고 느꼈습니다. 운영체제 등에서 나왔기 때문에
일어나지 말아야 할 일들,
상수가 있으면 일어나지 않기를 바라는 일들을 알고 있었습니다.
사실 제가 정말 원했던 건 읽기 전용과
쓰기 전용이었습니다. 하지만
C 언어 개발자들과 얘기해보니 const는 받아들이지만 읽기
전용과 쓰기 전용은 받아들이지 않았죠. 그게 더 나았을 텐데요. 하지만 괜찮습니다.
기본적으로 작은 상수를 만들 수 있고
이렇게 인터페이스를 만들 수 있습니다.
이렇게 하면 더 나은 인터페이스를 얻을 수 있죠. 이것도 계속
진행 중인 일입니다. RAII는
첫 2주 안에 있었습니다. 객체를 생성하고
초기화하는 생성자를 가지고,
최소한 객체의 불변성을 확립합니다.
캡슐화가 있으면 필요하고, 없으면
여전히 코드에 대해 생각할 수 있어야 합니다.
그리고 작업을 마쳤을 때, 자원을 획득했다면
다시 반환해야 합니다. 그렇지 않으면 자원
누수가 발생합니다. 사서들은 사람들이
책을 빌려가고 반납을 잊는다는 것을 알고 있습니다. 이는
인간의 본성이며, 우리는 이런 일을
대규모로 처리해야 합니다. 따라서 자원 해제는 자동화되어야 합니다.
그리고 당시에는 이것이
다르게 표현되었습니다. 제가 아직
용어를 만들어내지 않았기 때문입니다. 하지만 오늘날 우리는
이를 가지고 있고, 모두가 사용하고 있기를 바랍니다.
비메모리 자원의 예로는
파일 핸들, 락, 소켓,
셰이더 등이 있습니다. 좋습니다,
여기 자원 누수의 예시가 있습니다.
이는 순진하고 안전하지 않은 코드입니다. 저는 이것을
자주 보곤 했습니다. 사람들이 파일을 열고,
파일 핸들을 획득하고,
사용한 뒤 빠져나갑니다. 그리고 코드는
실제로 그리 좋지 않습니다. 때로는 두 페이지나 되고,
return 문이나 longjump 또는 예외가
그 안에 있어서 fclose에 도달하지 못합니다.
그래서 우리는 이런 코드를
갖지 말아야 합니다. 컴파일러가 보는 것, 우리가 보는 분석,
프로그래머가 보는 모든 것은
함수에서 포인터가 나오고
매뉴얼에는 그것을 다른 함수에 반환해야 한다고 되어 있습니다.
이는 좋은 코드가 아니며,
버그의 원인이었습니다. 그래서 우리가 하는 것은
코드에서 직접 표현하는 것입니다. 리소스에 대해 말할 때,
그것은 코드에 있어야 합니다. 어,
내가 그랬나요?
흠, 이상하네요.
순서가 잘못됐네요. 어쨌든, 객체 지향
프로그래밍은 잘 정의된 인터페이스, 클래스, 추상 기본 클래스,
오버로딩 등과 같은 유사한 것들에서 나왔습니다.
그런 것들이죠. 저기 체크무늬 재킷을 입은 사람이
올레 요한 달이고
다른 재킷을 입은 사람이 크리스텐 누고입니다.
그가 상속을 발명했고
기본적으로 객체 지향 프로그래밍을 만들었죠. 하지만
파일 핸들을 다루는 방법을 보여주는 슬라이드를 잃어버렸네요.
분명히 파일 핸들 클래스를 만들고
그 구조체가 파일을 닫는 거죠.
문제가 해결되었습니다. 우리는 이런 방식을 더 많이 해야 합니다.
언어의 진화는 물론 계속되었고, 템플릿은 우리에게
컴파일 시간에 구현을 선택할 수 있게 해주었습니다.
그리고 마침내 우리는 콘셉트를 얻었습니다. 우리는 정확하게
정의된 인터페이스를 가지게 되었고, 이를 일관되게 사용해야 합니다.
만약 제게 타임머신이 있다면, 88년으로 돌아가
콘셉트에 대해 말해주고 싶습니다.
그러면 우리는 훨씬 더 나은 템플릿을 가질 수 있었을 것이고,
제가 컨테이너를 설계하고 구현하는 것이 더 쉬웠을 것입니다.
그래서 우리는 배열과 포인터를 가지고 장난치지 않아도 됩니다.
그리고 이는 범위 검사를 가능하게 합니다. 컨테이너의 범위를 검사할 수 있는
충분한 정보가 있고, 주요 구현들은
벡터에 대한 범위 검사를 수행합니다.
불행히도 이에 대한 표준은 없습니다.
그래서 컴퓨터에 접근해서 다른 작업 없이
바로 범위 검사를 얻을 수는 없습니다.
이는 슬픈 일이며, 안전성과 알고리즘의 맥락에서 관련이 있습니다.
우리는 전통적인 STL의 begin-end 방식을 가지고 있었고,
이제 벡터나 어떤 컨테이너든 실제로 정렬할 수 있습니다.
이는 다시 말해서 만들 수 없는 버그가 있다는 뜻입니다.
예를 들어, end에서 begin으로 정렬하는 것과 같은 실수를
할 수 없습니다.
더 간단해지고, 더 명확해지며
더 안전해집니다. 스마트 포인터를 사용할 수 있지만,
여전히 포인터입니다.
우리는 범위 기반 for문과 span을 가지고 있습니다.
C 스타일 루프는 약간
의심스럽습니다. 즉,
n이 정말로 요소의 수인가요?
그리고 범위를
체크할 수 없습니다. 언어 관점에서
포인터에 범위 체크를 할 수 있는 충분한 정보가
없기 때문입니다. 이제 우리는 크기를 아는 span을 가지고 있습니다.
필요한 곳에서 범위 체크를 하거나, 저 예시처럼
전체를 처리할 수 있습니다.
Dennis Ritchie와 제가 80년대에
이 문제에 대해 논의했다는 점을 다시 언급하겠습니다.
그는 span과 같은 팻 포인터를 원했습니다.
저도 마찬가지였지만, 이를 얻는 데 시간이 걸렸습니다.
이는, Dennis가 C를 통제했다면
20년 전에 이것을 가졌을 것이라는 의미입니다.
그렇죠.
여기 사라졌던 슬라이드가 있습니다.
올바른 위치에 넣겠지만, 기본적으로 당신은
적절한 추상화를 통해 문제를 해결하여
적절한 검사를 수행하고 리소스를 해제합니다.
늦더라도 하는 게 낫죠.
좋습니다. 그래서 저는
순차적 이상을 작성했고, 기본적으로
첫 번째는 정적 타입 시스템을 암묵적으로 위반하지 않는 것입니다.
거기에는 꽤 많은 내용이 있습니다.
요점은 안전성과 더 안전한 것들에 대해 이야기할 때
이것이 오랫동안 문서화되어 왔다는 것입니다.
고수준은 어제 시작된 게 아닙니다. 언어의 가장 좋은
전통이며, 언어 사용의 이점입니다.
여기서 말하는 기능들을 사용하고,
삭제해야 하는 원시 포인터를 피하세요.
소유권 있는 원시 포인터를 사용하지 마세요.
원시 포인터를 인덱싱하지 마세요. 실제로 범위를
알 수 없기 때문입니다.
그리고 원시 포인터가 무언가를 가리키는지
확인하기 전에 역참조하지 마세요. 초기화되지 않은
변수를 사용하지 마세요. 여러분은 할 수 있습니다.
제가 2001년에 초보자를 위해 쓴
그 책에서는
17장까지 포인터와 배열을 보여주지 않습니다.
제가 그래픽을 만드는 법을 보여준 후에는 이렇게 할 수 있습니다.
좋은 C 언어,
더 높은 수준의 C는 일관된 기능 세트입니다.
실제로 저수준 작업을 할 필요가 없습니다. 정말로
그럴 필요가 없습니다. 완벽히 좋은 코드와 애플리케이션을
저수준으로 내려가지 않고도 작성할 수 있습니다.
따라서 안전을 원한다면,
C C를 작성하지 마세요.
그런 언어는 없지만, 사람들이 그것을 가지고 있다고
생각하는 용도는 분명히 있습니다.
그들은 그것이 C라고 말하고, 제가 이전 슬라이드에서
하지 말라고 한 모든 것을 하며, 주로 성능 문제를 주장하며
더 높은 수준의 기능을 피합니다.
그리고 그들은 측정을 하지 않습니다.
저는 때때로 대학원생들을 가르치는데,
그들은 여전히 측정 방법을 모르면서도 효율성에 대해 이야기합니다.
이런 일은 일어나지 말아야 합니다. 어쨌든, 우리는 입증 가능한
안전성을 향해 스타일을 발전시켜야 합니다. 왜냐하면 입증 가능한 안전성이
다루기 가장 쉽기 때문입니다. 생각하기에도
가장 쉽습니다. 그리고 평소처럼
저는 사람들을 설득하려고 노력하고 있습니다. 한계가 있지만,
조심하는 것만으로는 충분하지 않습니다. 우리는 공식화해야 합니다.
안전한 사용을 위한 규칙이 필요합니다. 우리는
사람들이 실제로 하려는 일을 하고 있는지
확인할 수 있는 방법을 제공해야 합니다. 즉,
여기 있는 누구도, 저를 포함해서,
코드를 작성하고 그것이 무언가를 한다고 생각했지만 실제로는 그렇지 않았던 경험이 없는 사람은 없을 겁니다.
저는 이런 일이 아마도,
매주 일어난다고 말하겠습니다. 제게는 말이죠. 그래서 저는
컴파일러를 좋아합니다. 그리고 우리는 가이드라인을
명확히 표현해야 합니다. 그래야 우리가
무엇을 말하고 있는지 이해할 수 있습니다. 길고 복잡한 규칙 목록이나
그리스 문자는 실제로 따르기
쉽지 않을 것입니다. 그리고 우리는 필요한 곳에서
가이드라인을 강제해야 합니다. 필요한 곳이란
우리가 코드에서 이것이 내가 원하는 것이라고
말해야 하는 곳을 의미합니다. 이에 대해서는 나중에 다루겠습니다.
현재 상황은 기본적으로 모든 것입니다.
제가 과거에 설명했고 이 발표의 나머지 부분에서 설명할
모든 것이 시도되었으며, 많은 것들이
대규모로 시도되었습니다. 예를 들어, 범위 검사, 문자열, 벡터, 스팬 등이 있습니다.
하지만 이 모든 것이 일관되고 통합된
전체로 통합된 곳은 없습니다. 그리고 그것이 우리가 해야
한다고 주장하는 것입니다. 많은 작업이
제가 이야기하는 것은 코어 가이드라인의 작업에 영향을 받았지만
우리는 가이드라인을 넘어서야 합니다. 제가 말했듯이, 조심하는 것은
확장성이 없고, 목표는 여전히 보장된
타입과 리소스 안전한 C입니다. 그리고 다른 것들도 있습니다.
이 타입과 리소스 안전은 매우 기본적이지만
다른 것들도 원하기 때문에
이러한 다른 것들이 무엇인지 명시해야 합니다.
그리고 오늘날 많은 것을 할 수 있습니다.
새로운 표준 릴리스를 기다릴 필요가 없습니다.
이것은 안전에 관한 것만이 아닙니다. 저는 더 높은 수준으로
올라가면서 코드 속도가 향상되는 것을 보았습니다.
무엇을 해야 하는지 더 명확하게 표현함으로써 말이죠.
제가 무슨 일이 일어날지, 무엇을 해야 할지 이해할 수 있다면
최적화 프로그램도 그렇게 할 수 있습니다. 그리고 종종
이점을 얻게 됩니다. 요즘 제가 디버깅하고
속도를 높이는 가장 좋은 방법 중 하나는 복잡한 것들을 제거하는 것입니다.
그러면 남은 것들에 대해
최적화 프로그램이 잘 처리할 수 있습니다.
남은 것에 대해
최적화 프로그램이 좋은 작업을 할 수 있습니다.
이런.
좋습니다, C 코어 가이드라인
또는 단순 정보용입니다. 이것은 고성능 칩과 프로세서를 만드는 기계입니다.
기본적으로 모든 고성능 칩을 만듭니다.
그리고 물론,
C언어로 프로그래밍되어 있습니다.
그들은 제게 연락해서 좋은 C 프로그래머를 고용하는 데
도움을 줄 수 있는지 물었습니다. 아니요, 그런 일은 하지 않습니다. 하지만 정말
뛰어난 C 프로그래머들은 정말 흥미로운 일을 할 수 있습니다.
일반적인 전략입니다. 우리는 잠재적 오류를 제거하기 위해
정적 분석에 의존합니다.
이는 일반적인 코드에서는 불가능합니다. 정확성을 증명할 수 없는
코드를 작성하는 것은 충분히 쉽습니다.
그리고 전역 정적 분석은 비용이 너무 많이 듭니다.
그래서 기본적으로 우리가 작성하는 것을 단순화하는 규칙이 필요합니다.
효율적이고 저렴하게 분석할 수 있는 것으로 말이죠.
지역 정적 분석입니다.
핵심 가이드라인을 위한 일부 분석기가 있어서
그런 작업을 수행하고, 이러한 규칙에 의존하는 것을 가능하게 하는 라이브러리를 제공합니다.
모든 것을 언어 수준에서 해야 한다면,
작업이 느려지고 작성하기 불편해져서
결국 하지 않게 될 것입니다. 올바른
추상화와 올바른 라이브러리가 있다면, 거의
모든 것이 쉬워집니다.
좋습니다, 여기에 철학이 있습니다. 이건 제가 만든 슬라이드인데,
거의 10년 전에 만들었죠. 몇 가지를 빨간색으로 강조했습니다.
빨간색으로요.
정적 타입 안전성은
컴파일 시간에 확인할 수 있고, 리소스 누수가 없으며,
불변 데이터를 선호합니다. 이 모든 것이 안전성과 관련됩니다.
다시 말해, 이는 C의 훌륭한 전통을 따르며
코딩 수준을 높이는 것입니다. 그리고 이러한 이상을 구현하기 위한
저수준 규칙들이 있습니다. 기본적으로 우리가 원하는 것을 명시하고
그것을 얻기 위해 근사치를 구하는
긴 규칙 목록을 만듭니다.
그것이 저수준의 것들입니다.
네, 그렇습니다.
그리고 핵심 가이드라인과
제가 다음에 말씀드릴 프로파일의 전략은
단순한 하위 집합만으로는 작동하지 않는다는 관찰입니다.
C의 하위 집합을 안전하거나 우아하거나
무언가 다른 것으로 만들고 싶다면,
가장 먼저 제거해야 할 것은 raw 포인터의 첨자 연산과
암시적 해제 없는 명시적 메모리
관리입니다.
소멸자에서부터요. 만약 그것을 제거한다면,
거의 아무것도 만들 수 없게 됩니다.
그래서 대신 더 나은 추상화를 구축합니다,
벡터, 스마트 포인터,
파일 핸들 클래스 등과 같은 것들이죠.
그리고 이것이 완성되면, 하위 레벨의 많은
복잡하고 위험한 것들을 제거할 수 있습니다.
이 전략은 효과가 있어 보입니다. 우리는 STL,
표준 라이브러리를 사용하고, 그리고 작은 지원 라이브러리인
GSL이 있습니다. 참고로 span이
여기서 나왔습니다. 많은 사람들이 여전히 GSL
span을 사용하는데, 범위 체크가 보장되기 때문입니다.
하지만 중요한 점은, 우리는 새로운 언어 기능을 추가하지 않습니다.
이 모든 것을 사용한 결과가 ISO 표준
C가 되길 원합니다. 새로운 언어를 설계하고 싶지 않습니다.
그건 너무 힘들고 시간이 오래 걸립니다.
저는 지금 당장 좋은 코드를 작성하고 싶습니다. 우리가
원하는 것은 스테로이드를 맞은 C이지, 어떤
불쌍한 서브셋이 아닙니다.
알겠죠? 그래서 우리는 실제로,
만약 제가 1시간 조금 넘는 대신 10시간이 있었다면,
이것을 자세히 설명할 수 있었을 겁니다,
들어보세요. 우리가 그 모든 것을 할 수 있다고 주장합니다. 물론,
이것은 기조연설이지 깊은 기술적 설명이 아니기 때문에 시간이 없습니다.
그래서 우리는 초기화되지 않은 변수, 범위 오류,
널 포인터 역참조, 리소스 누수, 댕글링 참조를 제거할 수 있습니다.
우리는 더 많은 것을 할 수 있습니다.
유니온은 배리언트를 사용하고,
캐스트는 그냥 하지 마세요. 오버로딩과
템플릿 프로그래밍을 제대로 하면 대부분의 비용을 제거할 수 있습니다.
언더플로우에 대해서는 제가 직접 작업하지 않았지만,
앞서 보여드린 엔진 사진에서
해양 디젤 엔진이 너무 커서 자세히 보면
5번 실린더 헤드 옆에 엔지니어가 보일 정도였습니다.
그리고 그것은 제네릭 프로그래밍으로 구동됩니다.
언더플로우와 오버플로우를 확인하는 제네릭 프로그래밍으로
실행되므로 가능합니다. 저는 단지 구체적인 제안이 없을 뿐입니다.
그리고 데이터 삭제 문제를 해결하는 방법도 있지만
그것은 최소한 하루가 걸립니다. 그래서 여기까지입니다.
초기화되지 않은 변수에 대해서는 그냥 하세요.
지연된 초기화를 위한 많은 영리한 방법들이 있습니다.
초기화처럼 작동하지만
코드가 취약해지고
복잡해집니다.
그리고 컴파일러는 문제가 없더라도 사람이 무슨 일이 일어나는지
보기 어려워집니다
모든 객체가 제대로 초기화되도록 하는 것이 중요합니다.
저는 모든 것을 초기화하는 것을 선호합니다.
예외적인 경우가 하나 있는데, 아마 더 많을 수도 있겠지만
큰 버퍼입니다. 저지연 작업을 하는 경우
먼저 버퍼를 초기화하고 나서 좋은 데이터로
채우고 싶지 않을 것입니다. 그러면 버퍼를 채우는 시간이 두 배가 됩니다.
초기화 규칙에서 벗어나야 할 산업이 꽤 많이 있을 것 같습니다
그래서 특정 항목을 표시할 수 있어야 합니다. 이것은 초기화되지 않았다고
코드에서 눈에 띄게 해서 확인하고 체크할 수 있도록 말이죠
이런 규칙들 중 많은 것들이
현실적이 되려면
일종의 예외 조항이 필요하고
그것을 명시적으로 해서 사람과 정적 분석기가
무슨 일이 일어나는지 이해할 수 있도록 해야 합니다.
범위 검사는 물론 원합니다.
개별 포인터의 첨자 연산은 원하지 않습니다.
C 스타일 코드를 작성한다면 놀라겠지만,
우리는 그것 없이도 할 수 있습니다. 벡터와 스팬이
범위 검사의 주요 예시인데
이들은
가능하며, 때로는 단순히 수행되고 있습니다
포인터로 확인할 수 있는 충분한 정보가 있기 때문에
하지만 그렇지 않습니다. 우리는 신뢰해야 합니다
범위를 올바르게 확인했다고
그리고 때로는 제대로 하지 못하므로
추상화를 사용하는 것이 훨씬 좋습니다. Range-for는
정말 좋습니다. 많은 정적 검사를
제거합니다. 시작과 끝만 확인하면 되기 때문입니다.
알고리즘은 좋습니다. 2주 전에 많은 학생들이
루프 측정을 수행했습니다.
그들은 정말 깊이 충격받았습니다
for-each와 accumulate가 직접
코딩한 C 스타일 루프를 눈에 띄게 이겼기 때문입니다.
학생들의 반응을 봤어야 했습니다.
당연히 그렇죠. 그들은 항상
저수준이 중요하고 효율적이라고 들어왔으니까요. 종종 널
포인터 참조가 있습니다. 포인터가 널이 아닌지
확인하는 것은 꽤 쉽습니다.
TSL에 그것을 위한 추상화가 있습니다
또는 정적 분석기가 사용 지점과
충분히 가까운 곳에 테스트가 있는지
확인하도록 할 수 있습니다.
다시 말하지만, 저는 분석기가 지나치게 영리해지는 걸 원치 않습니다
왜냐하면 저도 이해할 수 있기를 바라기 때문입니다. 리소스
누수가 없어야 합니다. RAII를 따르는
추상화를 일관되게 사용하세요.
우리에겐 많은 추상화가 있습니다. 노출된 new는
코드 냄새입니다. 사용하지 마세요. 노출된 delete도
마찬가지입니다. 애플리케이션 코드에서 사용하지 마세요.
이들은 추상화의 구현에
속합니다. 그리고 저는
이런 코드를 꽤 많이 봅니다,
주로 Java와 C#에서 온 사람들이
작성하는데, 거기서는 new를 써야
사용자 정의 클래스의 객체를
얻을 수 있습니다. 여기 가젯이 있습니다.
가젯 안에 뭐가 있는지 모릅니다.
잠금을 잡거나 파일 핸들을 잡을 수도 있습니다.
그리고 코드를 작성한 다음,
delete를 기억해야 합니다. 사람들은 꽤 자주
delete를 쓰고 싶지 않다고 말하며,
가비지 컬렉터를 원한다고 합니다. 하지만 가비지 컬렉터는
가젯 안에 무엇이 있는지 모르기 때문에 도움이 되지 않습니다.
즉시 해제되어야 하는 무언가일 수 있습니다.
명시적으로 해제되며, 그 코드는 물론
예외를 던져 빠져나갈 수 있고,
delete에 도달하지 않거나 반환할 수 있습니다.
아주 평범한 일입니다. 이것은 예외와는 관련이 없습니다.
저는 예외를 좋아하고, 이런 종류의 작업에 정말 유용합니다.
예외 없이도 문제가 생길 수 있습니다.
그래서 리소스 핸들로, 우리는
요즘 많은 unique 포인터와 shared
포인터를 사용하고, 그것이 어느 정도
문제를 해결합니다. 이제 구조체가 호출되고
올바르게 해제된다는 것이 보장됩니다.
간단하고 저렴합니다. 하지만 여전히 포인터이고
여전히 자유 저장소를 사용합니다. 할당이 있습니다.
그래서 실제로 우리가 해야 할 일은 더 많은
지역 객체를 사용하는 것입니다. 모든 것이
추가 표기법이나 추가
할당 없이 작동합니다. 물론 제한된 스택 공간을 가진
임베디드 프로세서용 코드를 작성하는 경우
이에 대해 주의해야 합니다. 하지만 일반적인 프로그래밍에서,
그리고 실제로 대부분의 프로그래밍에서 이것이 선호됩니다.
이것만이 여러분을 걱정하게 만들어서는 안 됩니다.
하지만 여러분은 naked new를 볼 수 있습니다
그리고 분석기는 쉽게 그것에 대해 경고합니다. 하지만 당신은
스마트 포인터에 대해서도 약간 의심스러워해야 합니다
왜냐하면 그것들은 정말 우아하지 않기 때문입니다.
좋습니다, 그래서 댕글링 포인터, 당신은 정말로
댕글링 포인터를 제거해야 합니다. 댕글링 포인터로 인해 발생할 수 있는 온갖 나쁜 일들이 있습니다.
당신은 그것을 통해 다른 사람의 메모리에 쓸 수 있고, 그것을 읽어
쓰레기 데이터를 얻을 수 있으며,
내용을 뒤섞을 수 있습니다. 이것은 정말 나쁩니다. 그리고 포인터라고 할 때 저는
객체를 직접 참조하는 모든 것을 의미합니다.
이것은 댕글링이 허용된다면 스마트 포인터일 수도 있습니다. 참조일 수도 있고,
무엇이든 될 수 있습니다. 그리고 우리는
그것들을 제거해야 합니다.
우리는 규칙들의 조합과
원시 포인터가 소유자가 아니라고 가정함으로써
그것들을 제거할 수 있습니다
그래서 우리는 여기서 메모리 관리 문제로부터
간섭을 받지 않아도 됩니다.
좋습니다, 여기 괜찮지 않은 코드 조각이 있습니다.
무해해 보입니다.
포인터를 얻고 삭제합니다. 음, 제가 만들고 있는
규칙에 따르면, 이것은 naked new이고,
분석기가 이를 거부할 것입니다. 그리고 이것은 좋습니다. 왜냐하면
g를 보면 무언가를 객체로 만들고,
그것을 f에 전달합니다
그리고 사용합니다. 아래의 사용은
댕글링 포인터의 사용입니다. 물론 실제 코드에서는
void f가 이렇게 보이지 않습니다.
아마 본 적 없는 어떤 라이브러리에 있을 겁니다
여러분이 본 적 없는 곳에 있겠죠.
하지만 정적 분석기는 이를 처리할 수 있습니다. 그리고 저는
제 코드에서 이런 일이 일어나지 않는다는 보장을 정말로 원합니다.
그리고 여러분이 해야 할 일은
모든 객체가 하나의 소유자만 갖도록 하는 것입니다.
이는 누가 삭제를 해야 하는지 알 수 있다는 뜻입니다,
닫기든 뭐라고 부르든 간에. 그리고 포인터는
원하는 만큼 많이 있을 수 있습니다. 단, 그것들이
소유자가 있던 위치 이후의 실행에
있지 않는 한에서요.
이는 꽤 간단한 모델이며
강제할 수 있습니다. 여기 예시가 있습니다.
여기 함수가 있는데 로컬 변수가 있고
g를 호출할 때 그 변수의 주소를 넘깁니다.
그리고 g는
그것을 사용합니다.
그런 다음 전역 변수에 저장합니다. 이는 중단되어야 합니다.
우리는 이를 분석하고 인자로 들어온 것을
전역 변수에 저장하는 것이 적절하지 않다고 말해야 합니다. 왜냐하면
그것이 유효한지 알 수 없기 때문입니다. 실행 후
종료합니다.
실행 후에 종료합니다.
반면에 포인터로부터 얻는 것들은 실제로 꽤 좋습니다.
이 규칙에 따르면 함수에 들어올 때 유효하고
함수를 떠날 때까지 유효할 것입니다. 왜냐하면 그것들은
스코프 외부에서 왔기 때문입니다. 그리고
여기서 우리가 가진 것은 무엇일까요? 컨테이너,
포인터 또는 무엇이든 기억하세요.
포인터는 컨테이너 안에 있을 수 있습니다. 여기서 저는
정수의 벡터를 사용했습니다. 나머지는 무언가였고,
그것은 괜찮습니다. 우리는 포인터, 반복자,
또는 무엇이든 컬렉션을 만들고 그것들을
호출될 함수에 전달합니다. 그리고 함수가 다시 돌아오면
모든 것이 괜찮습니다. 왜냐하면
포인터가 호출 코드에서 유효했다는 사실은
호출된 코드에서도 유효함을 의미합니다.
우리는 괜찮습니다. 우리는 실제로 모든 종류의
포인터를 제거할 필요가 없습니다.
이런 식으로 작동합니다. 반면에
그 나머지를 반환하는 것은 적절하지 않습니다. 왜냐하면 거기에는
범위를 벗어나게 될 로컬 요소에 대한 포인터가 있어
우리가 떠날 때 유효하지 않게 될 것이기 때문입니다.
무효화는 심각한 문제가 될 수 있으므로 이를 제거해야
합니다. 죄송합니다. 여기 우리는
전통적인 벡터 사용이 있습니다. 9를 push_back하면 모든 요소를 재배치할 수
있습니다. 괜찮습니다. 보통은
괜찮지만, G는 좋지 않은 방식으로
사용합니다. 먼저 첫 번째 요소에 대한
포인터, 첫 번째 요소에 대한 반복자를 가져온 다음,
함수를 호출하고 push_back을 수행한 후에
유지했던 포인터를 사용하려고 합니다.
이것이 reserve를 사용하는 이유이며
리스트와 같은 연결된 컨테이너를 사용하는 이유입니다. 요소들이 재배치되지 않기 때문입니다.
하지만 우리는 이 코드 조각이
나쁘다는 것을 감지할 수 있습니다.
이미 수행되었습니다. 그래서 우리가 실제로
하는 일은 무효화된 개념을 가지고 있습니다.
포인터가 요소를 재배치했을 수 있는 컨테이너의 요소를 가리킬 때,
그것을 무효화되었다고 부릅니다.
유효할 수도 있고 아닐 수도 있습니다. 그리고
우리는 다룰 수 있습니다
꽤 간단한 규칙으로 말이죠.
그리고 아니요, const 멤버 함수는
무효화하지 않습니다. 왜냐하면 그렇게 하려면
const에 나쁜 짓을 해야 하기 때문입니다. 캐스트나
그와 유사한 것을 사용해야 할 겁니다. 또한 분석기로 쉽게
검증할 수 있습니다. 반면에
우리는 const가 아닌 멤버 함수는 모두
무효화할 수 있다고 가정해야 합니다. 데이터에 접근할 수 있고
재배치할 수 있으며,
물건들을 옮길 수 있기 때문입니다.
코어 가이드라인과
프로파일에 새로운 주석이 필요하다고 생각합니다.
기본적으로 이것은 무효화하지 않는다고 말하는 것입니다. 비록 const가 아니더라도요. 표준
예시로 vector의 첨자 연산자가 있습니다. 재할당하지 않지만,
const일 수 없습니다. 그래서 이것도 쉽게 검증됩니다.
증명 가능한 것이죠. 따라서 완전히
안전하고 쉽게 할 수 있습니다. 소유권을
표현하세요. 평소처럼 소유권 추상화를 사용합니다.
높은 수준을 유지하고, 낮은 수준의 것들을 다루지 마세요.
가능하다면 말이죠.
그렇지 않습니다. 하지만 우리는 항상 우리의 규칙에 따라 작성되지 않은
코드를 어떻게 다룰지 고려해야 합니다.
예를 들어, 포인터가 많이 포함된 C 스타일
인터페이스가 있는 코드 같은 것들입니다. 그래서
우리는 코어 가이드라인에 주석을 달았습니다,
주로 세상이 그렇게 단순하지 않다는 사실을 다루기 위해서입니다.
우리가 모든 것을 소유하고 있지 않기 때문이죠. 이것을
owner라고 부릅니다. 이 포인터가 owner라고 말할 수 있습니다. 이것을 당신에게 넘기고 있고,
이 객체를 삭제하는 것이 당신의 일이라는 것을 알고 있습니다.
그렇게 할 수 있습니다.
기본적으로 이와 관련해 꽤 많은 작업이 이루어졌습니다,
그리고 owner를 복사할 수 있는 방법과 그렇지 않은 방법에 대한 규칙이 있습니다
안전한 것에서 유추할 수 있습니다. 여기서 자세히 설명하지는 않겠습니다.
슬라이드를 보고 계신다면
화면을 정지하고 이것이 무엇인지 볼 수 있습니다. 이제 저는
미래의 것들에 대해 이야기하고 싶습니다. 우리는 어디로 가야 할까요?
우리는 좋은 C++를 쓸 수 있습니다.
제가 합리적인 주장을 했기를 바랍니다
그리고 너무 많은 개발자들이 그렇게 하지 않습니다. 그들은 C++를 씁니다
이 신화적인 언어를,
가이드라인만으로는 충분하지 않습니다. 우리는 보증이 필요합니다,
부분적으로는 우리가 실수를 하기 때문이고, 부분적으로는 왜냐하면
우리는 실제 증명이 있으면 더 편안합니다.
그리고 우리는 정적 분석기와 컴파일러가 분석하는 것에 대한
새로운 기준이 필요합니다.
그래서 여기서 어떻게 진행할 수 있는지에 대한 몇 가지 대안이 있습니다
보장을 얻기 위해 C를 변경할 수 있습니다.
다른 언어를 사용하기 시작할 수 있는데, 이는
물론 다른 모든 새로운 언어의 지지자들이 제안하는 것입니다.
그리고 다양한 가이드라인을 적용할 수 있습니다.
그것이 제가 주장하는 프로필입니다. C를 수정하는 것에 대해
많은 다르거나 비교할 수 없는 아이디어들이 있습니다
C를 어떻게 변경할 것인가에 대한,
그리고 제가 말씀드린 문제들을 해결하는 방식으로
C를 변경하는 것에 대해서요.
그래서 C처럼 보이지 않을 것이고, 여러 제안들이 있습니다.
따라서 우리는 몇 년간의 지연과 혼란을 겪게 될 것이고,
단일 정리 언어는
단일 종류의 안전성을 제공할 것입니다,
물론 프로필 접근 방식을 채택하지 않는 한 말이죠.
그리고 그것은 많은 사람들이 말하는 것이 아닐 것입니다.
그리고 정리된 C는
고전적인 C 코드와 상호운용해야 할 것입니다
영원히 지속될 것입니다. 이것은 사실입니다.
이 수십억 줄의 코드는 사라지지 않을 것입니다.
그 중 많은 부분이 중요하고 정말 높은 품질입니다.
그래서 점진적인 도입이 필수적이며,
부분적인 도입도 필수적입니다.
그리고 C의 경우,
진화하도록 설계되었지만,
합리적이고 호환 가능한 방식으로 진화하도록 의도되었습니다.
이 마지막 진술을 받아들인다면, 사람들이 말하는 방식으로
수정되지는 않을 것입니다.
그리고 우리는 다른 언어를 사용해볼 수 있습니다.
안전성이 논거로 사용되는데,
주로 C와 C++에 대해서입니다.
그리고 전형적으로 C의 강점을 무시하고
대안들의 약점도 자주 무시합니다.
종종 안전 차원은 단지 메모리 안전성에 국한됩니다. 그것만으로는
충분하지 않고, 안전하지 않은 구조의 필요성은
크게 다루어지지 않습니다.
그리고 C와 C++를 포함한 다른 언어들과의
상호운용성 필요성은 언급되지 않는 경향이 있으며,
전환 비용이 엄청날 수 있다는 점도 거의
언급되지 않습니다. 물론 이는 자연스럽고 인간의 본성입니다.
당신은 자신의 주장을 펼치고 자신이 가진 것의
장점은 과대평가하고 반대 의견의 강점은
과소평가합니다. 하지만 우리는 이러한 논쟁을
더 진지하게 다뤄야 하고 몇몇 수치를 확보해야 합니다.
그리고 제가 본 바로는, 다른 어떤 언어로
C를 대체하려는 제안이 약
7가지 정도 있었습니다.
지금부터 40년 후에는 아마도
20가지 다른 언어들이 생길 것이고
그들은 상호 운용되어야 할 것입니다. 이는
어려울 것입니다. 어쨌든 살펴봅시다. 새로운 언어들,
새로운 자원들, 새로운 전문 사용자들이 있습니다.
물론 모든 새로운 언어는 C보다 더 단순하고, 깔끔하고, 안전하고
생산적이라고 주장됩니다. 반면에, 우리는
당시 Java에 대해서도 그런 말을 들었습니다. 저는 말했죠,
"그래, 살아남는다면 3배는 더 커지고
더 나아질 거야." 제 말이 맞았습니다. 이 주장은
대부분의 새로운 언어에 적용할 수 있고
종종 주장되는 우월성은 제한된 도메인에서의 것이며,
다시 말하지만 자주 C와 비교됩니다.
그리고 제가 주목한 한 가지는, 새로운 언어가 있을 때,
한 가지 제가 주목한 점은, 새로운 언어가 나올 때,
이는 C언어에서도 일어났습니다. 열정적인 프로그래머들이 모여
코드를 작성합니다. 그들은 평균보다 훨씬 뛰어납니다.
더 열정적이고, 더 많은 정보를 알고 있으며,
최신 기술을 모두 알고 있죠. 그러다
대수의 법칙에 부딪힙니다. 대규모로 사용되는
언어가 있으면, 개발자들의
품질과 열정은 평균 수준이 됩니다.
즉, 이 숫자는 작고 새로운 커뮤니티와
크고 오래된 커뮤니티를 비교하는 것이기 때문에
왜곡될 수 있습니다.
어떤 것을 전환하는 데 필요한 것에 대해
생각해 봤습니다. 1천만 줄의 시스템을 전환한다고 생각해 보세요. 그런 시스템이 많죠.
높은 신뢰성과 성능이 필요합니다. 그렇지 않다면
왜 전환을 하겠습니까? 안전상의 이유로요.
우수한 개발자는 하루에 n줄의
프로덕션 품질 코드를 완성합니다. n이 얼마인지 모르겠습니다.
어떤 종류의 코드인지에 따라 다르죠.
하지만 우리가 지금 얘기하는 중요한 소프트웨어의 경우,
아마도 5에서 10,
100, 연간 2000줄 정도라고
해 봅시다.
그 정도면 크게 틀리지 않을 겁니다.
그리고 1천만 줄의 시스템이
새로운 언어로 새로운 방식으로
처음부터 500만 줄로 작성될 수 있다고 가정해 봅시다.
절반 크기로요. 이는 매우 낙관적인 가정이지만,
만약 사실이라면, 500명의 개발자가 5년 동안
새 시스템을 완성하는 데 걸릴 것입니다. 그리고 기존 시스템은
교체될 때까지 5년 동안
유지보수되어야 합니다. 그래서 유능한 개발자의 총 급여는 얼마일까요?
연금, 건물,
난방, 냉방, 컴퓨팅 등 모든 것을 포함해서요.
미국에서는 50만 달러라고 합시다. 그리 멀지 않은 추정치입니다.
10만 달러 정도 오차는 있을 수 있지만 대략 이 정도입니다.
그러면 이 5년 동안
추가 비용은 대략
10억 달러가 들 것입니다.
100만 줄이면 나누고, 1억 줄이면 곱하면 됩니다.
이는 미국 개발자 기준으로 가정한 것입니다.
새로운 언어에 관련 경험이 있는
개발자를 찾을 수 있다면 좋겠지만,
그것도 종종 문제가 됩니다.
아웃소싱으로 비용을 줄일 수도 있겠죠.
하지만 그것도 쉽지 않습니다.
아웃소싱할 때 항상 그렇게 되는 것은 아닙니다. 그리고
아웃소싱에는 자체적인 문제가 있습니다. 특히
보안 같은 문제를 다룰 때 그렇죠.
그 비용을 극적으로 줄이는 방법은 명확하지 않습니다.
하지만 어쨌든,
저는 새 시스템이 기존 시스템 크기의 절반이 될 것이라고 가정했습니다.
그리 자주 일어나는 일은 아니지만,
문제에 대한 이해도가 높고, 더 나은 언어와 도구 등이 있다면
충분히 가능한 일입니다.
그리고 5년 동안 기능 확장은 없을 것입니다. 이건 어렵죠.
그리고 새 시스템은 작동할 것이고 제시간에 납품될 것입니다.
새 시스템은 작동할 것이고 제시간에 납품될 것입니다.
이 바보 같은 시스템에 무슨 일이 일어나고 있는 거죠?
아, 그 시스템에 무슨 일이 있었는지 알겠네요.
지금 당신이 보고 있는 걸 저는 보지 못하고 있습니다.
제가 보고 있네요. 알겠습니다.
물론 10억 달러나 1억 달러가
큰돈이 아닌 사람들도 있죠.
그래서 그 이유만으로 이 전체를 무시하지 맙시다.
1천만 줄의 시스템을 중간 규모라고 생각하는 사람들도 있습니다.
저는 이곳저곳에 물어봤습니다. 그래서
저는
이런 수치들은 점진적이고 진화적인 접근법에 대한
근거라고 생각합니다. 완전히 새로운 것으로
바꾸는 것이 아니라요. 물론 C일 수도 있고,
C와 다른 언어들의 조합일 수도 있습니다.
C와 원활하게 상호 운용되는 언어들 말이죠.
두 가지를 모두 포함하는 커뮤니티가 있을 수 있습니다. 저는
C를 유지하는 게 더 낫다고 봅니다. C는 앞으로 수십 년간
중요한 역할을 할 것이고, 우리는 계속 이를 발전시켜야 합니다.
표준 위원회는 집중해서 C를 개선해야 합니다.
그리고 인용구를 찾기 위해 알고 있는 것을 찾아보았습니다.
사람들은 인용구를 좋아하니까요. 게일의 법칙이라는 것이 있습니다.
"작동하는 복잡한 시스템은 항상
작동하는 단순한 시스템에서 진화한 것으로 밝혀진다."
다시 말해, 옛 시스템의 문제점 없이
완전히 새로운 시스템을 구축한다는 아이디어는
환상에 불과합니다. 하지만 매우 인기 있는 환상이죠.
저는 저 마지막 문장에 동의합니다.
프로파일에 대해 말하자면, 표준 C 코드로 어떻게 안전성을 보장할 수 있을까요?
가이드라인만으로는 충분하지 않습니다.
여기 프로파일 요약에 따르면
모든 것이 ISO C 표준을 따른다고 합니다.
가장 근본적인 보증은 완전한 타입 및 리소스
안전성입니다. 소유권은 반드시 DAG(방향성 비순환 그래프)를
구성해야 합니다. 그렇지 않으면
모델이 무너집니다. 순환이 있다면
공유 포인터나 약한 포인터로 처리할 수 있지만,
쉬운 증명을 위해서는 DAG를 고수하세요.
포인터 문제는 해결됐습니다. 앞서 말했듯이
점진적 변환을 통한 보증 제공이
지원되어야 합니다. 보증의 집합은
개방적입니다. 모든 사람이 원하는 보증을
알 수는 없습니다. 누군가는
안전하지 않은 보증을 원할 수도 있습니다.
최신 최적화 도구의 모든 안전하지 않은 기능을 사용할 수 있는
보증 말입니다.
즉, 개방된 집합이며 일부 기본적인 보증은
표준이 되길 원합니다.
타입과 리소스 안전성, 메모리 안전성,
범위 안전성, 산술 안전성 등이
표준화될 수 있을 것 같습니다.
표준화는 쉽지 않지만 가능합니다.
가정된 보증 집합은 코드에 명시되어야 합니다.
그렇지 않으면 어떤 분석을 적용해야 할지 모릅니다.
우리 코드에 대해 사용자로서 어떤 분석이
그 코드에 적용되었는지 모릅니다. 그리고 안전성에는
여러 개념이 있습니다. 전에도 말했지만
목록을 다시 보여드리는 게 좋겠습니다. 사람들은 종종
잊어버리고 지금 당면한 일상적인 문제에만
집중하는 경향이 있기 때문입니다.
여기 유형 및 리소스 안전성 정의가 있습니다.
기본적으로 모든 객체는 정의된 유형에 따라
접근됩니다. 좋은 정의입니다.
그리고 누수가 없습니다.
그럼 C는 어떨까요? C는?
언어는 아니지만 제가 좋아하지 않는 사용 스타일이라고 봅니다.
아마도 피할 수 없을 겁니다. C 라이브러리를 호출해야 하고
모든 보장을 갖춘 코어를 어떻게 만들지 생각해야 하니까요.
소유자 주석과 null 체크가 없는 것이
그 예시입니다. 우리는 단순히
모든 것의 새롭고 멋진 버전을 만드는 데만 집중할 수 없습니다.
정적 분석하기에는 너무 복잡합니다. 임의의 코드를 작성할 수 있다면
동적 링킹 비용과 홀딩 문제에 직면하게 됩니다.
임의의 C는 저수준 추상화를 다루는 데 집중합니다.
그래서 우리는
추상화 수준을 높여 분석이 가능하고
인간이 이해할 수 있는 지점까지 올립니다. 우리는
성능과 타입, 리소스 안전성을 중요하게 여깁니다.
그래서 아이디어는 정적 분석을 통한 보장입니다
분석이 가능하도록 코딩 규칙을 만들고
이러한 코드를 합리적으로 작성할 수 있는 라이브러리를 갖추는 것입니다
프로필은 단순히 관련 없는 테스트의 집합이 아닌
일관된 보장의 집합입니다.
그리고 프로필은
일련의 보장으로 명시되고
우리가 원하는 보장을 제공하는 규칙 집합으로
구현됩니다. 그리고 저는
이것이 너무 새롭고, 복잡하고, 생소하다고 말하는 사람들을 봤습니다.
그들은 단순하고 새로운 것을 원합니다.
첫 번째 C 버전처럼 45페이지로 정의할 수 있는
반짝이는 새 언어 말입니다. 저는
그렇게 생각하지 않습니다. 거기에는 투표가 있습니다. 여러분은 항상
새로운 것을 하지 말라고 들었고, 단지 오래된 것에
외관을 씌우라고 들었습니다. 저는 이것이
실현 가능하다고 생각하지 않습니다. 우리는 전반적인 접근법, 일반적인 접근법이 필요합니다.
각각의 개별 기술과 기능은
있습니다
이전에 여러 번 시도되었고, 그것은 좋습니다.
하지만 특정 작업에 대해서만이고,
그 중 어느 것도 모든 문제를 해결하지 못합니다. 따라서 통합된
일관된 접근 방식이 필요합니다.
프로필은 가이드라인을 넘어서야 합니다. 우리는
검증을 원하고 다루어야 할 것이 있습니다.
코드 주석을 제공해야 하고
프로필 혼합을 다루어야 합니다.
다른 보장 집합들. 대규모 시스템에서는
백만 줄의 코드가 모두 정확히
같은 규칙을 따른다고 상상할 수 없습니다. 그리고 할 수 있다면, 단순히
그 수를 1천만으로 늘리겠습니다.
그래서 우리는 프로필을 혼합하고 저는
우리가 가장 엄격한 것을 찾아야 한다고 생각합니다
검증되지 않고 보장되지 않은 기능을
언제 사용할 수 있는지에 대한 명세를
찾아야 합니다. 단순히 이 십만 줄은
확인되지 않았다고 말할 수는 없습니다. 그것으로는 충분하지 않습니다.
연결 리스트의 구현을 가지는 것이 좋을 수 있습니다.
두 페이지의 코드가 그것을 명시합니다.
따라서 여기에는 일부 설계 작업이 진행 중이며,
아직 개발 중입니다.
모듈 기반 제어를 제안하고 있습니다.
메모리 안전성, 타입 안전성이 제안되며
인코드 제어, 이 영역에서는 타입 안전성을 억제하고
이 영역에서는 타입 안전성을 강제합니다. 저는
너무 복잡하거나 변환하기 어려운 코드 조각이 있을 수 있어서
할 수 없습니다. 하지만 이 섹션에 대해서는
분석을 수행하고 싶다고 말할 수 있습니다
그리고 표준 프로필을 제안하면, 타입 안전성 범위
산술이 좋은 초기 세트가 될 것입니다.
이를 수행하는 데 필요한 구문에 대한
요약은 다음과 같습니다.
이는 진행 중인 작업입니다.
이에 대해 작성된 논문이 있고
찾아볼 수 있으며, 관련 강연도 있습니다.
기본적으로 아직 여기까지 오지 않았습니다.
고전적인 C와 CV 클래스, C11에서
매우 멀리 왔습니다.
우선 최신 C를 따라가지 못하는 사람들이
최신 상태를 따라잡도록 해야 합니다.
이는 모든 새로운 기능을 독점적으로 사용하거나
모든 새로운 작은 기능을 사용한다는 의미가 아닙니다.
아니요, 원하는 것을 정의하고
가장 간단한 방법을 찾는 것입니다. 핵심 가이드라인은 그에 대한 시도이며,
우리는 설명된 대로 프로파일을 표준화하기 시작해야 합니다.
그리고 물론 이것은
한두 사람이 할 수 있는 일이 아닙니다. 5년이면 가능할 수도 있겠지만,
우리에게 5년의 시간이 없다고 생각합니다. 그래서 어떻게 도울 수 있을까요?
어떻게 프로파일을 개선할 수 있을까요? 어떤 프로파일이 필요할까요?
프로파일 명세를 어떻게 가장 잘 형식화할 수 있을까요?
우리가 무엇을 할 수 있을까요?
저는 지금 '프로파일 라이트'와 같은 것을 꿈꾸고 있습니다.
이는 프로파일의 대부분의 보증을 제공하지만,
정적 분석기가 아직 준비되지 않아서
모든 최종 작업을 수행할 수 없는 것입니다.
그리고 우리가 단순화할 수 있는 라이브러리 구성 요소는 무엇일까요?
저는 pushback이 없는 din 배열을 사용해왔습니다.
이를 통해 누군가 다른 스레드에서 pushback을 하는 것을 걱정하지 않고
동시 시스템에서 사용할 수 있습니다.
아마도 우리는 더 많은 그런 것들이 필요할 것 같습니다.
그리고 저는 GitHub을 설정하고 있습니다.
거기에서 사람들이 제안을 올릴 수 있고,
제가 초안과 그런 것들을 올릴 것입니다.
이를 통해 우리는 이런 종류의 작업을
합리적인 시간 내에 수행할 수 있는
커뮤니티를 만들 수 있습니다. GitHub는
아직 라이브가 아니지만,
오늘 오후에 라이브가 될 것입니다.
네, 감사합니다.
질문이 있나요? 질문 시간이 있나요?
아니면 제가 너무 길게 얘기해서 시간이 없나요?
질문이 있으시면 마이크로 나와 주세요.
저기에도 마이크가 하나 있습니다.
안녕하세요, 감사합니다. 예를 들어 말씀하신
특정 프로파일에서 pushback이 없는 벡터에 대해
프로파일이 어떤 경우에는 멤버 함수를 제거하거나
아니면 그 멤버 함수의 동작만 다르게 할 것이라고 생각하시나요?
죄송하지만 질문을 잘 이해하지 못했습니다.
특정 상황에서 pushback이 없는 벡터 클래스를 원할 수 있다고 언급하셨습니다.
네, 그렇습니다.
그래서 특정 멤버 함수를 제거하는 프로파일이 있을 수 있겠네요.
그것도 한 방법이지만, 제가 생각한 방식은 아닙니다.
다른 방식으로 했는데, 그 이유는
표준 벡터 구현을 실제로 수정할 수 없었기 때문입니다.
예를 들어, 제 학생들은 범위 검사를
벡터에 대해서는 구현을 건드리지 않고는 할 수 없습니다.
그리고 여러 구현이 있어서 그렇게 하지 않습니다.
마찬가지로 무효화의 경우에는
다른 클래스를 사용했는데, din array라고 불렀고
GSL에서 찾을 수 있을 것입니다. 이 클래스는 단순히 그 연산이 없었습니다.
그것이 다른 방법입니다. 그리고 만약 여러분이
표준 위원회나 표준 라이브러리 공급업체가 아니라면,
그렇게 해야 합니다.
그래서 저는 그렇게 했습니다.
그렇게 했습니다.
불변 데이터에 대한 질문입니다. 가변 데이터보다
불변 데이터를 선호한다고 말씀하셨습니다. 동시에 유명하게도
C의 string 클래스는 가변적입니다.
불변 string 클래스에 대한 많은 논의를 보았지만
실제로 널리 채택되지는 않았습니다.
불변 string 클래스에 대해 많이 들었지만,
저는 가끔 문자열을 변경하는 것을 좋아하고
기본적으로 불변으로 만드는 것이 더 좋다는
일관된 주장을 보지 못했습니다.
이점은 무엇이고 문제점은 무엇인가요?
그러한 제안이 없다면,
우리는 그것을 얻지 못할 것입니다. 게다가,
코드가 너무 많아서, 거의 확실히
다른 불변적인 것의 예시가 있을 것입니다.
하지만 누군가는 철저하고 논리적이며
가능하면 데이터에 근거한 주장을 해야 합니다.
불변 문자열이 좋은 이유에 대해. 이것이
정확성의 문제인가요? 성능의 문제인가요?
이 모든 것에 대해? 저는 그런 종류의 주장을 보지 못했습니다.
감사합니다.
당신이 제안한 많은 것들이
정적 분석기나 다른 도구에 의해 컴파일러와 별도로 강제되는 것을 알아챘습니다.
제가 새로운 C 프로젝트를 개인적으로 또는 직장에서 설정할 때 관찰한 문제 중 하나는
추가 도구를 빌드 체인과 CI에 통합하는 것이 노력이 필요하고,
생산 규모에서는 사소한 노력이 아니라는 점입니다.
이 과정을 더 쉽게 만들 수 있는 제안이 있나요? 도구
통합을 더 간단하게 만드는 방법에 대해? 도구 체인과
관련된 몇 가지 문제가 있고, 네, 새로운 것을
도구 체인에 추가하기는 어렵습니다.
그리고 CDH의 일반적인 문제는 우리가 많은 것을 가지고 있다는 것입니다.
우리는 결코 그냥... C에 그래픽 시스템이
없는 게 아니라 많은 그래픽 시스템이 있습니다.
우리는 많은 빌드 시스템, 많은 정적 분석 시스템을 가지고 있습니다.
우리는 많은 빌드 시스템, 많은 정적 분석 시스템
제가 바라는 것은 프로필이
사람들이 특정 프로필을 지원하는
정적 분석기를 만들도록 장려하고,
빌드 시스템, 컴파일 시스템이
이것이 필요하다는 것을 인식하고
설치된 정적 분석기를 사용하는 것입니다.
제가 하고 있는 많은 부분이 실제로
컴파일러 자체에 포함될 수 있습니다. 컴파일러는 정적
분석기이며, 요즘은 꽤 정교한 정적
분석기입니다. 가장 간단한 것은
초기화되지 않은 데이터 규칙인데,
이미 더 복잡한 작업을 수행하고 있습니다
초기화 여부를 감지하는 데에 있어서
말입니다. 하지만 저는
프로필 주석의 아이디어가
이 문제를 해결하는 데 도움이 될 것이라고 생각합니다. 감사합니다.
C의 안전성에 대한 새로운 개선이
언어에 새로운 주석, 새로운 타입을 추가하는 것 같습니다.
기본값이 실제로 안전한 것이 되고
안전하지 않은 것을 사용하려면 실제로
특별히 요청해야 하는 때가 올 것이라고 생각하십니까?
게다가 호환성을 유지하려면
확장을 통해 작업해야 하므로
언어에서 기능을 효과적으로 제거할 수 없습니다.
우리는 여러 번 기능 폐기를 시도했지만
심지어 호환되지 않는 변경사항도
많은 문제를 일으켰습니다. 그래서 그 방향으로 가지 않겠습니다.
제가 실제로 추구하는 것은
가이드라인을 통해 언어 사용을 단순화하는 것입니다.
그리고 가이드라인을 따르면 더 단순한 언어를 다루게 됩니다.
실제로 void에 대한 포인터의 포인터와 같은 복잡한 것을 알 필요가 없습니다.
분석이 그런 코드를 작성하지 못하게
막아줄 것이기 때문입니다.
따라서 언어를 확장하고,
강제할 수 있는 더 단순한 언어의 부분 집합을 만드세요.
감사합니다.
안녕하세요, 언어 기능으로 const에 대해 말씀하실 때
write-only를 추가하고 싶다고 간단히 언급하셨습니다.
더 나은 인터페이스를 만들 것이라고 하셨는데,
write-only의 사용 사례에 대해 어떤 생각을 하고 계신지,
그리고 대안이 있는지 궁금합니다.
네, write-only에 대해 말씀해 주세요.
알겠습니다. 제가 이해하지 못했네요.
아, const에 대해 언급하실 때
읽기 전용과 쓰기 전용에 대해 말씀하셨고,
const처럼 쓰기 전용이 있었다면
더 나은 인터페이스가 되었을 거라고 하셨죠.
const 예시는 우리가 초기부터 어떻게
더 안전한 언어를 만들려고 노력했는지
보여주는 예시일 뿐입니다.
실수하기 어렵고 이해하기 쉬운
언어를 만들려고 했죠. 그리고 제가 단순히
읽기 전용인 const만 있었던 게 아니라
쓰기 전용도 있었다는 역사적 사실을 언급했는데,
그건 넣을 수 없었습니다. 알겠습니다. 네, 감사합니다.
윌. 그래서 이런 생각이 드는데요,
때로는 함수가 스레드 안전하다거나
I/O 작업을 수행한다는 것을 표현하고 싶을 수 있죠?
말씀하신 프로필을 구현하기 위해 내부적으로
태그 디스패치를 사용할 수 있을까요?
그건 생각해보지 않았네요. 즉석에서 하는
코멘트입니다만, 네, 스레드 안전
애노테이션이 있을 수 있겠네요.
그것이 아마도
프로필의 일부입니다. 프로필은
불가피하게 다른 프로필들로 부분적으로 구성될 것입니다.
현재 핵심 가이드라인에는
메모리 안전성과
타입 안전성이 있습니다. 제 생각에는
타입과 리소스 안전성을 구성하는 세 가지가 있을 것 같습니다.
그리고 스레드 안전성이
프로필의 일부가 될 것이라고
생각합니다.
제가 정말 보고 싶지 않은 것은 총 50개 또는 100개의
요청할 수 있는 항목들입니다.
그렇게 되면 혼란스러워질 것입니다.
현재의 정적 분석기를 보면 자유로운 선택을
제공하는 경향이 있습니다.
그리고 그것은 매우 자주 일관된
보장 세트로 합산되지 않습니다.
그래서 네, 그것은 무언가의 후보가 될 수 있지만,
정확히 무엇인지는 잘 모르겠습니다.
컴파일 시간 리플렉션이 언어의 일부라면,
외부 분석기 대신 개념이나 함수에 대한 개념을 사용하여
대부분의 정적 분석 검사를 구현할 수 있을 것이라고
생각하십니까?
아니요, 그렇게 생각하지 않습니다.
그것은 다룹니다. 저는 정적 리플렉션을 보고 싶지만,
이것은 다른 문제들의 집합을
다룬다고 생각합니다.
네, 발표 감사합니다. 제어된 환경에서,
코드의 작성자일 때 좋은 예시가 있다고 생각합니다.
하지만 만약, 어떻게, 어떻게 생각하세요? 어떻게 안전성을 개선할 수 있을까요
C, C++ 라이브러리처럼 포인터를 전달하는
라이브러리를 다룰 때 말이에요.
무엇을 할 수 있을까요? 그것은 제가 언급한
프로파일 혼합의 문제입니다. 당신은,
import나 include에 주석을 달 수 있습니다
어떤 가정을 할 수 있는지에 대해
당신이 가져오는 것에 대해
그게 당신이 할 수 있는 전부입니다.
프로파일의 부분 집합을 다룰 수 있습니다,
임의로, 부분 집합과 분리된 집합을 다룰 수 있지만,
임의의 보증 집합은
기계적으로 다루기에는 너무 어렵습니다.
그래서 우리는 몇 가지 주석을 달고
사람들이 실제로 이해하고 무엇을 다루는지
보려고 노력해야 할 것입니다.
그리고 이 문제는 수십 년 동안 해결되지 않을 것입니다.
기본적으로, 범위가 있다면
우리는 이것이 문제라는 걸 알아야 합니다. 최선을 다해 대처해야 하지만
완전히 제거할 수는 없습니다.
감사합니다.
안녕하세요. 발표에서 concept을 언급하신 것을 들었습니다.
우리는 직장의 라이브러리에서 그것을 사용하려고 합니다.
우리가 겪는 문제는 그것이
코드를 더 복잡하게 만들고 다른 사람들이 유지보수할 때
이해하기 어렵게 만든다는 것입니다.
그리고 concept을 사용함으로써 얻는 실제 이점을 찾지 못했습니다.
concept의 이점과 올바르게 사용하기 위한
가이드라인 리소스에 대해
자세히 설명해 주실 수 있나요? 물론이죠. 저는
컴퓨터 과학 분야가 아닌 코드에서
특히 통신 소프트웨어에서 성공적으로 사용했습니다.
그리고 매우 유용하다는 것을 알았습니다.
피해야 할 한 가지는 사람들이 requires 절을
requires로 사용하고,
보증의 저수준 사용을 하는 것입니다.
그것은 엉망진창을 만듭니다. 당신이 그렇게 했는지는 모르겠지만, 그것이
제가 본 실패 사례 중 하나입니다. 사람들은 자신들이 사용하고 있다고 생각합니다
모듈이 아닙니다. 그들은 모듈을 만들기 위해 어셈블리 코드를 사용하고 있습니다.
그리고 어셈블러만큼 성공적이며,
적절한 개념을 구축하는 데는
약간의 경험이 필요합니다. 사람들이 모든 것에 대해
절대적으로 최소한의 개념 제약을 가져야 한다는 아이디어로 개념을 구축하려고 시도하는 것을 봤습니다.
다시 말하지만, 너무 많은 개념이 생기고
기억할 수 없게 됩니다. 제가 개념에 대해 글을 쓰거나
개념에 대해 이야기할 때, 저는 개념이 설계되어야 한다고 말합니다.
구성을 장려하도록 말입니다. 즉,
개념은 충분히 높은 수준이어야 하며
많은 곳에서, 많은 알고리즘에서 사용될 수 있어야 합니다.
따라서 사람들이 '미만' 개념을 만들고 다른 사람이 '이하' 개념을 사용한다면,
혼란스러운 상황으로 향하게 됩니다. 반면에
표준에 있는 것처럼 정렬 개념을 만든다면,
네 가지 연산을 모두 포함하여
더 나은 방향으로 나아갈 수 있습니다.
물론 우리가 다루지 않은
문제 영역이 있을 수 있지만,
대부분의 경우에는
제가 본 문제들은
우리가 다루지 않은 영역이었습니다.
하지만 대부분의 경우 문제가 있었습니다.
그런 식이죠. 그건 미숙함 때문입니다.
사용의 미숙함이죠. 마치 사람들이
코딩을 시작할 때 좋은 코드를 쓰지 못하는 것과 같습니다.
초보자의 실수를 하는 거죠.
제가 무례하다고 생각하지 않으셨으면 좋겠습니다만,
그것이 가능성 중 하나일 수 있다고 제안드립니다.
당신의 작업을 분석해보시고 정확히 무엇이
잘 작동하지 않았는지 파악하실 수 있다면,
그것에 대해 듣고 싶습니다.
네, 감사합니다. 이게 다인 것 같네요. 감사합니다.