【问题标题】:Pointer arithmetic on raw data原始数据的指针算法
【发布时间】:2013-07-30 21:58:30
【问题描述】:

所以我必须处理一些结构数据,我必须以一种奇怪的方式压缩这些数据以用于 MPI_Send/Recv。

没有办法轻松地将它转换为指向我想要操作的已知类型的指针,然后沿着索引(因为我已经将结构压缩到连续数据中,不能假设任何关于对齐的事情),所以我必须通过指针算术来完成它。问题是,为了与 MPI 保持一致,此数据以 void* 形式给出,而 void* 上的指针运算是非法的。

我的问题主要是文体问题:有没有比强制转换为 char* 然后执行我的指针算术更好的方法? 采用 void* 时的效率考虑是什么,强制转换到 char*,对它做我的事情,然后再转回 void*?我无法想象指针转换会非常昂贵。

G'day,非常感谢。

【问题讨论】:

    标签: c serialization mpi void-pointers pointer-arithmetic


    【解决方案1】:

    有什么特殊原因需要您自己打包缓冲区吗?你真的在 MPI 操作之前压缩了连续缓冲区中的数据吗?如果是这样,您的压缩加上传输时间必须低于简单地进行传输。如果是这样,那么我可以将其视为很好的理由。

    如果您实际上只是为了 MPI 操作而打包在一个连续的缓冲区中,那么解决问题的更好方法是自己停止打包数据,而是使用 MPI 派生数据类型

    您可以使用“MPI 派生数据类型示例”之类的内容进行网络搜索,并获得比我可以在此处简要写的更好的解释。

    【讨论】:

    • 问题是结构包含的东西不是数据,而是我想要发送的值堆栈的索引。有点像指针。直接发送这些东西是没有意义的,就像发送指针一样,所以我需要以某种方式“取消引用”它们。仅使用派生的数据类型机制来实现这一点既棘手又不可能,因为此堆栈上每个值的位移相对于包含其索引的结构的开头不是恒定的。
    【解决方案2】:

    您的解决方案是合理的。很多时候我都做过这样的事情:

    void handle_raw(void* data) {
        // Use a uint8_t so pointer arithmetic is at a byte-level.
        uint8_t* p = data;    
        uint16_t value;
    
        // Read a 2-byte value at an arbitrary offset.
        value = *(uint16_t*)(p + 0x42);
    
        // Write a 2-byte value at an arbitrary offset.
        *(uint32_t*)(p + 0x12) = 0xDEADBEEF;
    }
    

    当然,您应该使用常量作为偏移量,并执行适当的边界检查。

    【讨论】:

    • 在这种情况下是安全的。在许多架构上,如果指针不是 2 字节对齐的,您的代码将失败。此外,类型双关存在别名问题:使用联合。
    【解决方案3】:

    指针转换完全免费。去做吧。

    具有类型的指针完全是语言级别的概念。当您深入到硬件级别时,指针只是一个恰好用作内存地址的整数。

    确实必须小心严格别名,当投射指针时,我认为char *被定义为安全的。

    [好吧,在某些情况下,在某些架构上,指针除了“只是整数”之外还有特殊处理,但你可能会忽略这些。还有一些 ABI,其中不同的指针类型不同的(例如 FDPIC),但同样是其他人的问题。]

    【讨论】:

    • 啊,那很简单。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    • 2011-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多