완전 왼쪽 시프트 오버플로(Exact Left Shift Overflow)
완전 왼쪽 시프트 오버플로(Exact Left Shift Overflow)
본문
@shlExact는 비트가 빠져나가면(오버플로가 나면) 컴파일 타임이든 런타임이든 그 자리에서 에러를 일으켜요. 값이 사라지는 걸 허용하지 않는 엄격한 연산이라 생각하면 돼요.
컴파일 타임일 때를 볼게요:
comptime {
const x = @shlExact(@as(u8, 0b01010101), 2);
_ = x;
}
$ zig test test_comptime_shlExact_overflow.zig
/home/ci/work/zig-bootstrap/zig/doc/langref/test_comptime_shlExact_overflow.zig:2:15: error: overflow of integer type 'u8' with value '340'
const x = @shlExact(@as(u8, 0b01010101), 2);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0b01010101(85)를 두 칸 왼쪽으로 밀면 0b101010100(340)이 되는데, u8은 8비트라서 이 값이 못 들어가요. 그래서 최상위 비트가 흘러넘치고, 컴파일러가 바로 오류를 뱉어요.
런타임일 때는 어떨까요:
const std = @import("std");
pub fn main() void {
var x: u8 = 0b01010101; // runtime-known
_ = &x;
const y = @shlExact(x, 2);
std.debug.print("value: {}\n", .{y});
}
$ zig build-exe runtime_shlExact_overflow.zig
$ ./runtime_shlExact_overflow
thread 973279 panic: left shift overflowed bits
/home/ci/work/zig-bootstrap/zig/doc/langref/runtime_shlExact_overflow.zig:6:5: 0x11e82c1 in main (runtime_shlExact_overflow.zig)
const y = @shlExact(x, 2);
^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:788:64: 0x11e7bbb in callMain (std.zig)
if (fn_info.param_types.len == 0) return wrapMain(root.main());
^
/home/ci/work/zig-bootstrap/out/host/lib/zig/std/start.zig:248:5: 0x11e75e1 in _start (std.zig)
asm volatile (switch (native_arch) {
^
(process terminated by signal)
여기서는 x가 컴파일 타임에 알 수 없는(runtime-known) 값이라 컴파일러가 미리 잡아주지 못해요. 실행해 보면 left shift overflowed bits라는 메시지와 함께 패닉이 터져요. 즉 @shlExact는 값이 흘러넘치는 순간을 결코 조용히 넘기지 않아요 — 컴파일 타임엔 컴파일 에러, 런타임엔 패닉.
더 알아보기
@shlWithOverflow와@shlExact처럼 "정밀한" 연산 계열과, 오버플로를 허용하는 일반<<시프트의 차이를 함께 보면 이해가 빨라져요.@shlExact의 반대 역할을 하는@shrExact(오른쪽 정밀 시프트)도 같은 원리로 동작해요.