【问题标题】:What does cast do exactly?cast 到底是做什么的?
【发布时间】:2015-07-24 11:53:57
【问题描述】:

我在玩整数数组散列和从一个表示到另一个表示的不同方法。我最终得到以下结果:

void main(string[] args) {
    import std.algorithm, std.array, std.conv, std.stdio, std.digest.md;

    union hashU {
        ubyte[] hashA;
        int[]   hashN;
    };

    hashU a;
    auto md5 = new MD5Digest();

    a.hashN = [1, 2, 3, 4, 5];

    /* Using an union, no actual data conversion */
    md5.put( a.hashA );
    auto hash = md5.finish();
    writeln(hash);
    // [253, 255, 63, 4, 193, 99, 182, 232, 28, 231, 57, 107, 18, 254, 75, 175]

    /* Using a cast... Doesn't match any of the other representations */
    md5.put( cast(ubyte[])(a.hashN) );
    hash = md5.finish();
    writeln(hash);
    // [254, 5, 74, 210, 231, 185, 139, 238, 103, 63, 159, 242, 45, 80, 240, 12]

    /* Using .to! to convert from array to array */
    md5.put( a.hashN.to!(ubyte[]) );
    hash = md5.finish();
    writeln(hash);
    // [124, 253, 208, 120, 137, 179, 41, 93, 106, 85, 9, 20, 171, 53, 224, 104]

    /* This matches the previous transformation */
    md5.put( a.hashN.map!(x => x.to!ubyte).array );
    hash = md5.finish();
    writeln(hash);
    // [124, 253, 208, 120, 137, 179, 41, 93, 106, 85, 9, 20, 171, 53, 224, 104]
}

我的问题如下:演员是做什么的?我原以为它会和 .to 一样!或联合技巧,但似乎并非如此。

【问题讨论】:

    标签: casting type-conversion union d


    【解决方案1】:

    我认为 Colin Grogan 说得对,但他的措辞有点混乱。

    使用联合,数组被简单地重新解释,根本没有计算/计算发生。 int[] 的指针和长度被重新解释为引用 ubyte 元素。之前:5 个整数,之后:5 ubytes。

    强制转换比这更聪明一点:它调整数组的长度,以便它引用与以前相同的内存。之前:5 个整数,之后:20 ubytes (5*int.sizeof/ubyte.sizeof = 5*4/1 = 20)。

    联合和强制转换都将整数的字节重新解释为 ubytes。也就是说,int 值 1 将产生 4 ubytes:0,0,0,1 或 1,0,0,0,具体取决于字节序。

    to 变体将每个元素转换为新的元素类型。之前:5 个整数,之后:5 个 ubytes,其值与整数相同。如果其中一个 int 无法转换为 ubyte,to 将抛出异常。

    在各种转换之后打印元素可能有助于澄清发生了什么:

    void main()
    {
        import std.algorithm, std.array, std.conv, std.stdio;
    
        union hashU
        {
            ubyte[] hashA;
            int[]   hashN;
        }
        hashU a;
        a.hashN = [1, 2, 3, 4, 5];
    
        writeln( a.hashA ); /* union -> [1, 0, 0, 0, 2] (depends on endianess) */
    
        writeln( cast(ubyte[])(a.hashN) );
            /* cast -> [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0]
            (depends on endianess) */
    
        writeln( a.hashN.to!(ubyte[]) ); /* `to` -> [1, 2, 3, 4, 5] */
    }
    

    【讨论】:

      【解决方案2】:

      据我所知,cast 只是告诉编译器开始与您已将其转换为类型的内存块进行对话。

      您示例中的最后两个选项实际上将数字转换为新类型,一些 实际 工作也是如此。这就是为什么它们最终是相同的值。

      前两个示例中的问题是 int[] 在内存中比 ubyte[] 大。 (每个元素 4 个字节与每个元素 1 个字节)

      我已经编辑了你的前两种方法:

          /* Using an union, no actual data conversion */
      md5.put( a.hashA );
      auto hash = md5.finish();
      writefln("Hash of: %s -> %s", a.hashA, hash);
      // Hash of: [1, 0, 0, 0, 2] -> [253, 255, 63, 4, 193, 99, 182, 232, 28, 231, 57, 107, 18, 254, 75, 175] 
      // notice 5 bytes in first array
      
      /* Using a cast... Doesn't match any of the other representations */
      md5.put( cast(ubyte[])(a.hashN) );
      hash = md5.finish();
      writefln("Hash of: %s -> %s", cast(ubyte[])(a.hashN), hash);
      // Hash of: [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0] -> [254, 5, 74, 210, 231, 185, 139, 238, 103, 63, 159, 242, 45, 80, 240, 12] 
      // notice 20 bytes (4 x 5 bytes) in first array
      

      首先,您正在读取 ubyte[] 字节的长度。在第二个中,您将 int[] 的长度转换为 ubyte[]。

      编辑:可能不清楚。联合非常愚蠢,它只是将所有值存储在同一个内存中。当您读取其中任何一个时,它只会读取该内存的 X 位,具体取决于您正在读取的类型的长度。

      因此,因为您正在读取 int[] THEN 转换它,它会读取所有 20 个字节并将它们转换为 ubyte[]。这当然不同于仅读取 ubyte[] 变量的 5 个字节。

      我觉得我说得有道理:)

      【讨论】:

        【解决方案3】:

        cast 是一个 D 运算符,当开发人员需要执行显式类型转换时使用。

        【讨论】:

          猜你喜欢
          • 2015-08-06
          • 2013-09-02
          • 2014-01-02
          • 2013-10-10
          • 2017-05-08
          • 2022-01-20
          • 2012-10-17
          • 2017-06-15
          • 2011-05-20
          相关资源
          最近更新 更多