• d的指针算术


    原文
    如下在ldc更好C下编译:

    import core.stdc.stdio;
    import core.stdc.stdlib;
    
    struct MemoryBlock {
      char* ptr;
      ulong length;
    }
    
    void* ptr = cast(void*)0x7a7;
    
    void* right() {
      return cast(MemoryBlock*)(ptr + MemoryBlock.sizeof);
     //在括号间转换整个`式`.取正确的值!
    }
     //以上代码向`ptr`加了`16`个字节
    
    void* wrong() {
      return cast(MemoryBlock*)ptr + MemoryBlock.sizeof;
     //先转换`'ptr'`变量,然后加上数字.得到错误的值...
    }
     //上面的代码向`ptr`加了`16*MemoryBlock.sizeof`字节`(16*16)`,因为先转换`ptr`,`+1`才是正确的
    
    char* return_address_wrong() {
      MemoryBlock* local_ptr = cast(MemoryBlock*)ptr;
      return cast(char*)(local_ptr + MemoryBlock.sizeof);
     //转换了整个式.但得到了错误的值`!!!!`为什么`???`
    }
     //因为加的是`16`字节块的指针,而不是单字节的`void*`
    
    char* return_address_right() {
      MemoryBlock* local_ptr = cast(MemoryBlock*)ptr;
      return cast(char*)local_ptr + MemoryBlock.sizeof;
     //现在我先转换`'local_ptr'`变量,然后加上数字,但这次得到了正确的值`..`,
    }
    //这是单个字节.
    
    extern (C) void main() {
      printf("期望位置:", ptr + MemoryBlock.sizeof);
      printf("正确位置: %p\n", right());
      printf("错误位置: %p\n", wrong());
    
      printf("返回地址(错误)): %p\n", return_address_wrong());
      printf("返回地址(正确): %p\n", return_address_right());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    T*+10==10 * T.sizeof
    64位系统上,MemoryBlock.sizeof16.
    参考:
    结果值是指针加上(或减去)第二个操作数乘以第一个操作数指向类型的大小.
    因为加的是16字节块指针,而不是单字节的void*.

    C和D根据基础值类型实现指针算术.即,向char*,加1加为基础地址加1,但向int*加1,则是基础地址加int.sizeof而不是1.即:

    int[2] x;
        int* p = &x[0]; // 假设这是1234地址
        p++;//p现在为1238,而*不是*1235(int.sizeof==4)
    
    • 1
    • 2
    • 3

    因为更容易操作.
    如,如果是指向4个有符号32位整数的数组,那么可简单地给指针递增1.
    如果是原始字节,那么必须给指针加4才能移动到下个元素.
    如果要移动到循环中的下个元素,这是反直觉的.
    这是惯用法:

    foreach (i; 0 .. list.length)
    {
        (*cast(int*)(ptr + i)) = i;
    }
    
    • 1
    • 2
    • 3
    • 4

    比较:

    foreach (i; 0 .. list.length)
    {
        (*cast(int*)(ptr + (i * 4))) = i;
    }
    
    • 1
    • 2
    • 3
    • 4

    可这样:

    foreach (i; 0 .. list.length) {
      (cast(int*)ptr[i]) = i;
    }
    
    • 1
    • 2
    • 3

    只要稍微移动右括号.可用指针加括号标记法.
    假设ptrvoid*,这些都是等价的:

    (cast(int*) ptr)[i] = whatever;
    *((cast(int*) ptr) + i) = whatever;
    *(cast(int*) (ptr + i * int.sizeof)) = whatever;
    
    • 1
    • 2
    • 3
  • 相关阅读:
    ON java 8 对象创建
    麒麟系统安装找不到安装源!!!!设置基础软件仓库时出错
    每日一题 —— LC. 790 多米诺和托米诺
    JVM的相关知识
    「程序员转型技术管理」必修的 10 个能力提升方向
    论文阅读: A Unified Sequence Interface for Vision Tasks
    Symfony Vue 教程
    springboot基于javaweb的社区留守儿童帮扶系统毕业设计源码101603
    【无标题】axios的ts封装,记录一下(Vue3项目)
    29、Java高级特性——集合:集合框架、Collections类
  • 原文地址:https://blog.csdn.net/fqbqrr/article/details/128197849