kubo39's blog

ただの雑記です。

D言語のcast

D言語で型変換したかったら基本は std.conv.to 使うのが安全である。

import std.conv;

void main()
{
    int a = 1;
    long b = a.to!long;
    assert(b == 1);
}

std.conv.toは安全であるが、安全であるということは制約が強いということでもある。例えば以下のコードはOverflowを検知し例外を投げる。

import std.conv : to;

void main()
{
    auto a = -11; // int
    ulong b = a.to!ulong;
}
$ rdmd -fPIC to.d 
std.conv.ConvOverflowException@/home/kubo39/dlang/dmd-2.072.1/linux/bin64/../../src/phobos/std/conv.d(445): Conversion negative overflow
----------------
??:? pure @safe bool std.exception.enforce!(bool).enforce(bool, lazy object.Throwable) [0xde158fb2]
??:? pure @safe ulong std.conv.toImpl!(ulong, int).toImpl(int) [0xde158f34]
??:? pure @safe ulong std.conv.to!(ulong).to!(int).to(int) [0xde158f00]
??:? _Dmain [0xde158ef0]
??:? _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv [0x6dda5387]
??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x6dda52b3]
??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).runAll() [0x6dda532c]
??:? void rt.dmain2._d_run_main(int, char**, extern (C) int function(char[][])*).tryExec(scope void delegate()) [0x6dda52b3]
??:? _d_run_main [0x6dda5217]
??:? main [0xde159047]
??:? __libc_start_main [0x6d5413f0]

こういうことがやりたいときもたまにあって、そういうときは cast を使う。

import std.stdio;

void main()
{
    auto a = -1;
    uint b = cast(uint) a;
    b.writeln;
}

castは危険な操作を許容する。例えば以下のようなコードはコンパイルが通り、未定義動作となる。

void main()
{
    ubyte[4] arr = [0, 1, 0, 0];
    auto ptr = cast(uint*) arr.ptr;
    assert(*ptr == 256);
    auto ptr2 = cast(ulong*) ptr;
    import std.stdio;
    (*ptr2).writeln;  // 未定義
}
(dmd-2.072.1)( ՞ਊ ՞) :~/dev/misc $ rdmd -fPIC cast.d 
139972984176896
(dmd-2.072.1)( ՞ਊ ՞) :~/dev/misc $ rdmd -fPIC cast.d 
140411070841088
(dmd-2.072.1)( ՞ਊ ՞) :~/dev/misc $ rdmd -fPIC cast.d 
140045998620928
(dmd-2.072.1)( ՞ਊ ՞) :~/dev/misc $ rdmd -fPIC cast.d 
256