🌟
Zigでコンパイルエラーになって書き方がわからないとき
Zig言語は型に厳しい
Zigは型に関して厳しい言語です。
以下のようなコードを書いたときに、たぶん型変換のことでエラーになるだろうなあと思いつつコンパイルしてみると
a.zig
const std = @import("std");
const expect = std.testing.expect;
fn func(x: i32) u8 {
return x & 0xff;
}
test "truncate" {
try expect(func(0x1234) == 0x34);
}
やはり、こんなエラーになりました。
$ zig test a.zig
a.zig:5:14: error: expected type 'u8', found 'i32'
return x & 0xff;
~~^~~~~~
a.zig:5:14: note: unsigned 8-bit int cannot represent all possible signed 32-bit values
a.zig:4:17: note: function return type declared here
fn func(x: i32) u8 {
^~
referenced by:
test.truncate: a.zig:9:16
remaining reference traces hidden; use '-freference-trace' to see all reference traces
Cで書いてZigに変換してみる
こんなときはC言語で書いてみて、zig tranlate-c
でZigに変換すると答えがわかります。
a.c
#include <stdint.h>
uint8_t func(int32_t x)
{
return x & 0xff;
}
コンパイルエラーにならないことを確認。
$ zig cc -c a.c
$
zig translate-c
は引数にインクルードファイルのディレクトリを指定する必要があるのですが、毎回するのが面倒なのでbash scriptにしました。gistに置きました。
$ c2zig a.c
変換結果はこのようになっていました。
a_translated.zig
...
pub export fn func(arg_x: i32) u8 {
var x = arg_x;
return @bitCast(u8, @truncate(i8, x & @as(c_int, 255)));
}
...
これを参考にして、以下のようにa.zigを修正します。
a.zig
const std = @import("std");
const expect = std.testing.expect;
fn func(x: i32) u8 {
return @bitCast(u8, @truncate(i8, x & 0xff));
}
test "truncate" {
try expect(func(0x1234) == 0x34);
}
テスト実行。
$ zig test a.zig
All 1 tests passed.
OKでした。
よく考えてみると@truncate
することは & 0xff と同じことなので冗長を省くと以下のようにできます。
fn func(x: i32) u8 {
return @bitCast(u8, @truncate(i8, x));
}
関連
Discussion