오버플로우의 개념
overflow의 사전적 의미는 넘쳐 흐르다. 범람하다 등의 뜻이다.
Swift언어의 오버플로우는 대략 다음과 같다.
각 정수형은 담을 수 있는 수의 크기가 있다.
자료형 | 범위 | 부호여부 | 크기 |
Int8 | -128 ~ 127 | 부호 있음 | 8 비트 |
Int16 | -32768 ~ 32767 | 부호 있음 | 16 비트 |
Int32 | -2147483648 ~ 2147483647 | 부호 있음 | 32 비트 |
Int64 | -9223372036854775808 ~ 9223372036854775807 |
부호 있음 | 64 비트 |
UInt8 | 0 ~ 255 | 부호 없음 | 8 비트 |
UInt16 | 0 ~ 65535 | 부호 없음 | 16 비트 |
UInt32 | 0 ~ 4264967295 | 부호 없음 | 32 비트 |
UInt64 | 0 ~ 18446744073709551615 | 부호 없음 | 64 비트 |
사용 가능한 수의 범위를 넘으면 오버플로우가 발생하게된다.
Int8은 8비트로 정수형을 포함하게 된다. 맨 첫 비트는 부호비트이므로 실질적 수는 7비트로 표현하게 되는데,
각 자리수는 1, 2, 4, 8, 16, 32, 64 와 같다 이를 모두 더하면 127이된다.
양수의 경우 최상위비트가 0이며 나머지가 모두 1일경우 127이다. 0 ~ 127
음수의 경우 최상위비트가 1이다. 가장 작은 음수값은 -2^-7 = 128이 된다.
근데 Int8인 변수에 만약 32767을 넣게되면 정해진 8비트의 자리에 16비트를 넣게되고 허용 가능한 자리수를 넘치게된다. 그럼 정해진 메모리를 벗어나 다른 메모리에 접근하게된다.
쉽게 1Byte의 영역에 2Byte를 넣으려고하면 정해진 메모리를 벗어나 다른 공간에 영향을 미치게 되고
오버플로우가 발생한다.
Swift에서의 overflow
C언어나 Obj-C언어의 산술연산자에서는 오버플로우를 허락했다.
255까지 담을 수 있는 UInt8에 256을 담으면 0으로 순환하는 방식으로..
하지만 Swift는 오버플로우를 기본적으로 허락하지 않는다. 크래시가 발생한다!
특정 경우에, 특정 패턴을 구현하기 위해 오버플로우를 허용하는 경우가 필요할 수 있는데 이런 경우를 위해 "오버플로우 연산자"를 마련해 놓았다.
오버플로우연산자
&+ : 오버플로우 더하기 연산자
&- : 오버플로우 빼기 연산자
&* : 오버플로우 곱하기 연산자
부호가 없는 경우
// &+ : 오버플로우 더하기 연산자
var a = UInt8.max // 현재 변수 a에 UInt8타입의 최대값이 들어있음(255)
a = a &+ 1 // 오버플로우 더하기 연산자로 1을 더하기 ==========> 최소값(0)으로 이동
//a = 0b11111111 &+ 0b00000001
// &- : 오버플로우 빼기 연산자
var b = UInt8.min // 현재 변수 b에 UInt8타입의 최소값이 들어있음(0)
b = b &- 1 // 오버플로우 빼기 연산자로 1을 빼기 ==========> 최대값(255)으로 이동
//b = 0b00000000 &- 0b00000001
부호가 있는 경우
/**=========================
- Int8타입의 범위: -128 ~ 127
===========================**/
// &+ : 오버플로우 더하기 연산자
var a1 = Int8.max // 현재 변수 a1에 Int8타입의 최대값이 들어있음(127)
a1 = a1 &+ 1 // 오버플로우 더하기 연산자로 1을 더하기 ==========> 최소값(-128)으로 이동
//a1 = 0b01111111 &+ 0b00000001
// &- : 오버플로우 빼기 연산자
var b1 = Int8.min // 현재 변수 b1에 Int8타입의 최소값이 들어있음(-128)
b1 = b1 &- 1 // 오버플로우 빼기 연산자로 1을 빼기 ==========> 최대값(127)으로 이동
//b1 = -0b10000000 &- 0b00000001
// &* : 오버플로우 곱하기 연산자
var c1 = Int8.max // 현재 변수 c에 Int8타입의 최대값이 들어있음(127)
c1 = c1 &* 2 // 오버플로우 곱하기 연산자로 2 곱하기 ==========> 비트 한칸씩 이동
//c = 0b01111111 &* 2