본문 바로가기
Topos Uranos

요약

이 수업은 식과 그 연산자를 다루는 강좌의 셋째 단원을 마무리한다. 산술 연산자에서 라이브러리 함수에 이르는 개념의 사슬을, 식 트리와 각 노드의 자료형, 조건과 그 대수, 단락 평가, 부수 효과와 평가 순서, 그리고 비트를 거쳐 다시 세운다. 그 가운데 어느 언어에서나 통하는 것을 C++에 고유한 것과 구별한다. 단원의 정의되지 않은 동작을, 컴파일러가 찾아내는 것, 새니타이저가 찾아내는 것, 아무도 찾아내지 못하는 것과 함께 모은다. 마무리 평가에서 입문 평가의 기능들을 되풀이한다. 그리고 단원 전체를 엮는 여섯 도전 과제로 끝난다.

학습 목표

  1. 강좌의 어떤 식에 대해서든, 그 트리와 각 노드의 변환으로부터 값, 자료형, 효과를 예측한다.
  2. 복합 조건을 쓰고 부정하며, 단락 평가를 써서 그렇지 않으면 의미가 없어질 연산을 보호한다.
  3. 의미가 없는 식(단원의 정의되지 않은 동작 목록)을 알아보고, 각각을 찾아내는 도구를 말하며, 정의되지 않은 동작이 없도록 다시 쓴다.
  4. 주어진 계산에 대해 산술, 비트 연산자, 수학 라이브러리 가운데 무엇을 쓸지 고르고, 그 선택의 근거를 댄다.
  5. 단원에서 배운 것 가운데 어느 언어에서나 통하는 것과 C++에 고유한 것을 구별한다.

단원에서 이룬 것

이 단원은 값을 확실하게 예측할 수 있는 식을 만드는 법을 가르치려 했다. 어떤 연산이 먼저 이루어지는지, 결과가 어떤 자료형인지, 어떤 부수 효과가 있는지, 어떤 식이 의미가 없는지이다. 그 목적은 도입 수업이 이미 안다고 밝힌 것, 곧 2단원의 자료형, 그 값의 범위, 그 변환에만 기대어 이루어졌다. 도입 수업이 문제를 제기할 때 쓴 여섯 질문의 프로그램은 이제 컴파일러가 읽듯이 읽을 수 있고, 식 하나하나를 고칠 수 있다.

산술 연산

산술 연산 수업은 다섯 산술 연산자의 정확한 동작을 정했다. 정수 나눗셈은 0 쪽으로 버리고, 몫이 의미를 가지는 한 항등식 (a / b) * b + a % b == a 식을 만족한다. 따라서 나머지는 0이 아닐 때 피제수의 부호를 가진다. 그래서 -7 / 2 식은 −3-3의 값을, -7 % 2 식은 −1-1의 값을 가지며, 홀수인지는 n % 2 != 0 식으로 묻는다. 이 수업은 이것을 유클리드 나머지 ((a % b) + b) % b 식(b>0b > 0일 때)과 연결하고, 둘 다 써서 양을 분해했다. 우선순위와 결합 방향에 따라 식 트리를 그리고, 일반 산술 변환으로 각 노드의 자료형을 정하는 법을 가르쳤다. 마지막으로 의미가 없는 몫(0으로 하는 정수 나눗셈과, 최소 정수를 −1-1로 나눈 것)과 중간 결과 오버플로를 다루었다. 중간 결과 오버플로는 최종 결과가 들어가더라도 정의되지 않은 동작이 되기에 충분하다.

관계와 논리

관계와 논리 수업은 조건이 bool 타입의 식이며 트리 안에 제자리가 있음을 가르쳤다. 관계 연산자는 산술보다 약하게 결합하고, && 연산자는 || 연산자보다 강하게, ! 연산자는 그 모두보다 강하게 결합한다. 문장을 조건으로 옮기는 법과, 1 < x < 5 식이나 day == 6 || 7 식처럼 다른 의미로 컴파일되는 조건을 알아보는 법을 가르쳤다. && 연산자와 || 연산자는 첫째 피연산자로 결과가 정해지지 않을 때만 둘째 피연산자를 계산하며, 이 단락 덕분에 연산의 왼쪽에 둔 보초로 그 연산을 보호할 수 있음을 보였다. 마지막으로 복합 조건을 부정하는 드모르간 법칙과 그 한계를 다루었다. 수가 아닌 값에서는 !(a < b) 식이 a >= b 식과 동치가 아니다.

대입, 부수 효과, 정의되지 않은 동작

대입, 부수 효과, 정의되지 않은 동작 수업은 식의 값과 그 효과를 구별했다. 대입은 대입된 값을 가지며 변수를 바꾸는 식이고, x++ 식은 원래 값을, ++x 식은 새 값을 가진다. 식 트리는 그 가지들을 계산하는 순서를 정하지 않으므로, 같은 변수에 대한 두 효과나 효과와 읽기가 서로 순서 없이 일어나면 그 식은 의미를 잃는다는 것을 보였고, C++17이 무엇에 순서를 주었고 무엇을 미지정으로 남겼는지 밝혔다. 네 등급(정의된 동작, 구현 정의 동작, 미지정 동작, 정의되지 않은 동작)의 목록을 모았고, 컴파일러는 프로그램에 정의되지 않은 동작이 없다고 가정하고 추론한다는 것을 설명했으며, 목록의 각 경우마다 어떤 도구가 그것을 찾아내는지 말했다.

비트와 수학 라이브러리

비트와 수학 라이브러리 수업은 정수가 비트의 나열이기도 하다는 것을 가르쳤다. & 연산자, | 연산자, ^ 연산자는 각 열에 논리 연결사를 적용하고, ~ 연산자는 모든 비트를 뒤집으며, 시프트는 2의 거듭제곱을 곱하거나 그것으로 나눈다. 단, 시프트 양이 음수가 아니고 자료형의 폭에 이르지 않아야 한다. 이것들로 비트를 확인하고, 켜고, 끄고, 반전하는 마스크를 만들었다. 이 연산자들은 관계 연산자보다 약하게 결합하므로 x & 1 == 0 식은 보이는 대로 묻지 않는다는 것, 그리고 ^ 연산자는 거듭제곱이 아니라는 것을 경고했다. 마지막으로 라이브러리를 다루었다. <cmath> 헤더, <numbers> 헤더, <numeric> 헤더, <bit> 헤더는 올바르고 검증된 계산을 제공하며, 각자의 사전 조건이 있다. 절댓값의 사전 조건이 그 예로, 최소 정수에는 절댓값이 존재하지 않는다.