Remainder Division by Zero — 0으로 나눗셈 나머지를 구하면
Remainder Division by Zero — 0으로 나눗셈 나머지를 구하면
나머지 연산에서 0으로 나눌 때 어떤 일이 벌어지는지를 보여주는 섹션이에요. 컴파일 타임이든 런타임이든, a % b에서 b가 0이 되면 Zig는 이를 **불법 동작(illegal behavior)**으로 간주해요. 정수 나눗셈에서 0으로 나누는 건 정의할 수 없는 연산이기 때문이죠. 이걸 그냥 '값이 이상하게 나온다' 정도로 넘기지 말고, Zig가 이 상황을 어떤 식으로 막아주는지 직접 확인해 볼게요.
본문
먼저 컴파일 타임(compile-time) 상황을 볼게요. comptime 블록 안에서 a % b를 계산하는데, b가 0이에요.
comptime {
const a: i32 = 10;
const b: i32 = 0;
const c = a % b;
_ = c;
}
이 코드를 zig test로 실행하면 컴파일러가 계산을 시도하는 순간 바로 걸러줘요.
$ zig test test_comptime_remainder_division_by_zero.zig
error: division by zero here causes illegal behavior
const c = a % b;
^
error: division by zero here causes illegal behavior라는 메시지가 뜨죠. 컴파일 타임에는 b가 0이라는 게 명확하게 보이니까, 컴파일러가 코드를 실행하기도 전에 이게 잘못된 연산이라고 잡아내는 거예요. 정확히 어느 위치의 코드가 문제인지 캐럿(^)으로 짚어 주는 것도 확인할 수 있어요.
이번에는 런타임(runtime) 상황을 볼게요. 실행 중에 값이 정해지는 변수라서 컴파일러가 미리 알 수 없는 경우예요.
const std = @import("std");
pub fn main() void {
var a: u32 = 10;
var b: u32 = 0;
_ = .{ &a, &b };
const c = a % b;
std.debug.print("value: {}\n", .{c});
}
a와 b가 var로 선언되어 있고, .의 주소를 넘겨서 컴파일러가 최적화로 값을 알아내지 못하게 막아 둔 상태예요. 이렇게 하면 컴파일 타임에는 걸리지 않고, 실제로 프로그램이 실행될 때 a % b에 도달해서야 문제가 드러나요.
$ zig build-exe runtime_remainder_division_by_zero.zig
$ ./runtime_remainder_division_by_zero
thread 974883 panic: division by zero
/home/ci/work/zig-bootstrap/zig/doc/langref/runtime_remainder_division_by_zero.zig:7:17: 0x11e82b0 in main (runtime_remainder_division_by_zero.zig)
const c = a % b;
^
...
(process terminated by signal)
실행 결과는 panic: division by zero로 끝나요. 컴파일 타임에는 커버할 수 없는, 실행 중에야 밝혀진 0-나눗셈을 런타임 안전성 검사(runtime safety checks)가 잡아서 패닉을 일으키는 거예요. 이 섹션은 정수에서 %(나머지) 연산과 /(나눗셈) 연산을 0으로 나누려 할 때 공통으로 적용되는 규칙이에요.
더 알아보기
- 0으로 나누기와 같은 불법 동작을 런타임에 잡는 장치 — Runtime Safety
- 나머지 연산이지만 0으로 나눌 때 같은 오류를 내는 내장 함수 — @rem
- 0으로 나누는 나눗셈(Division by Zero) 사례
- 정확히 나눗셈을 수행하는 함수 — @divExact