코틀린의 양의 정수 타입
일반적인 다른 언어들과 같이 코틀린에서도 부호 없는 정수(0 보다 크거나 같은 정수)형 데이터 타입을 다루기 위한 다양한 타입들이 코틀린 1.5버전부터 지원되기 시작했다. 글의 제목이 있는 UByte, UShort, UInt, ULong이 그 타입들이다.
변수를 각 타입으로 만드는 방법은 어렵지 않다. 우리가 Float을 선언할 때 접미어로 f를 붙이는 것처럼 접미어로 U를 붙여주면 된다.
fun main() {
val uByte: UByte = 100U // U를 붙여주어야 한다.
val uShort: UShort = 10_000U // U를 붙여주어야 한다.
val uInt: UInt = 1_000_000U // U를 붙여주어야 한다.
val uLong: ULong = 100_000_000UL // U를 붙여주어야 한다.
println("uByte: $uByte")
println("uShort: $uShort")
println("uInt: $uInt")
println("uLong: $uLong")
}
위 코드를 실행해보면, 일반 숫자와 같이 출력되는 것을 확인할 수 있다.
각 타입의 범위
기존에 Byte가 8비트, Short가 16비트, Int가 32비트, Long이 64비트를 할당 받던 것과 같이 UByte, UShort, UInt, ULong 각각은 순서대로 8비트, 16비트, 32비트, 64비트를 할당 받는다. 최소 값은 0이며 따라서 256개의 값을 가질 수 있는 UByte는 0~255 범위의 값을, 65356개의 값을 가질 수 있는 UShort는 0~65,535 범위의 값을, UInt는 0~4,294,967,295 범위의 값을, ULong은 0~18,446,744,073,709,551,615 범위의 값을 가진다. 이를 표로 나타내면 다음과 같다.
타입 이름 | 할당 비트 수 | 범위 |
UByte | 8 | 0~255 |
UShort | 16 | 0~65,535 |
UInt | 32 | 0~4,294,967,295 |
ULong | 64 | 0~18,446,744,073,709,551,615 |
Unsigned 타입은 어떻게 구현되는가?
Unsigned 타입은 내부적으로 Signed Type의 값을 래핑하는 형태로 구현된다. 다음은 그 예시인 UByte이다. constructor 내부에서 Byte를 감싸고 있는 것을 볼 수 있다.
public value class UByte @kotlin.internal.IntrinsicConstEvaluation @PublishedApi internal constructor(@PublishedApi internal val data: Byte) : Comparable<UByte>
그렇다면 어떻게 음을 표현하는 값을 양의 값으로 바꾸는 것일까? 바로 And 연산을 통해 그렇게 한다. Unsigned Byte 내부에 있는 진짜 데이터인 Byte는 데이터를 Unsigned 값으로 바꾸기 위해 0xFF와 And 연산을 수행한다.
예를 들어 -128이라는 값을 가진 Byte를 생각해보자. 이 Byte는 바이트로 표현하면 '10000000'이 된다. 이를 0xFF 즉 '11111111'과 And 연산을 수행해보자.
1000 0000
1111 1111
---------
1000 0000
그러면 여전히 값은 1000000이 되며, 이 값은 Unsigned Byte 에서는 128이 된다.
이를 확인하기 위해 128의 값을 가지는 UByte를 Byte로 변환해 출력해보면 -128이 나오는 것을 볼 수 있다.
fun main() {
val uByte: UByte = 128U
println("Byte: ${uByte.toByte()}") // -128 출력
}
UByte 뿐만 아니라, UShort, UInt, ULong 모두 내부에 Short, Int, Long을 래핑하는 형태로 구현되어 있으며, 비슷한 방식을 통해 데이터의 변환을 수행한다.
public value class UShort ... internal constructor(@PublishedApi internal val data: Short) : Comparable<UShort>
public value class UInt ... internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>
public value class ULong ... internal constructor(@PublishedApi internal val data: Long) : Comparable<ULong>
정리
- Unsigned 타입을 통해 0보다 크거나 같은 값을 다룰 수 있다.
- Unsigned 타입은 내부에 Signed 타입을 래핑하고 있다.