c++ - Memcpy 实现,严格别名

标签 c++ c memcpy strict-aliasing

在学习 c 的过程中,我实现了自己的 memcpy 函数。我在函数中使用了更广泛的类型 (uint32_t)。 (为简单起见,该函数仅限于 4 的倍数的类型并且数据正确对齐)

void memcpy4( void* dst , void* src , int size )
{
    size /= 4;

    for ( int i = 0 ; i < size ; i++ )
        ((uint32_t*)dst)[i] = ((uint32_t*)src)[i];
}

我阅读了一些关于类型双关和严格别名的文章,我相信上面的函数违反了规则。正确的实现是这样的,因为您可以使用字符:

void memcpy4( void* dst , void* src , int size )
{
    for ( int i = 0 ; i < size ; i++ )
        ((char *)dst)[i] = ((char *)src)[i];
}

我尝试通过 union 进行一些转换,但结果也是无效的。

如何用更广泛的类型实现这样的功能而不违反严格的别名规则?

最佳答案

使用多于单字节拷贝实现memcpy的方法是使用非标准C。

标准 C 不支持使用非字符类型实现 memcpy

Quality C 实现提供了一个优化的 memcpy 实现,它使用多个单字节拷贝执行高效复制,但它们使用特定于实现的代码来执行此操作。他们可以通过使用诸如 -fnostrict-aliasing 之类的开关编译 memcpy 实现来告诉编译器代码中的别名规则将被违反,依赖于已知的特定 C 实现的特性以确保代码能够工作(如果您编写编译器,您可以设计它以便您的 memcpy 实现工作),或者通过编写 memcpy用汇编语言。

此外,C 实现可以优化出现在源代码中的 memcpy 调用,用执行操作的直接指令或简单地更改程序的内部语义来替换它们。 (例如,如果您将 a 复制到 b,编译器可能根本不执行复制,而可能只是从后续代码访问的 a 加载b.)

如果您使用的是 GCC 或 Clang,要在违反别名规则的情况下实现您自己的专用复制操作,请使用 -fnostrict-aliasing 编译它。如果您使用的是其他编译器,请查看其文档以找到禁用别名规则的选项。 (注意:我使用的 Apple 的 GCC 默认禁用严格别名并接受 -fstrict-aliasing 但不接受 -fnostrict-aliasing。我假设非 Apple GCC 接受-fnostrict-aliasing.)

如果您使用的是良好的 C 实现,您可能会发现 memcpy4 的四字节复制实现的性能不如 native memcpy,具体取决于视情况而定。

关于c++ - Memcpy 实现,严格别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21217126/

相关文章:

c - 并行运行 while 循环

c - 日期类型/scanf()

c - “大小 8 的无效读取”- Valgrind。尝试用来自其他结构的数据填充结构

c++ - 为什么我不能在 memcpy 中使用 const 参数?

c++ - 如何平滑地移动 Sprite ?

c++ - 如何比较两个 vector 的相等性?

c - 测试信号量如何工作

c++ - 最终使用 NEON Copy 但不使用 memcpy 的 ARM Linux 内存碎片

c++ - 状态机 - 保存状态、事件和 pFunc 的结构

c++ - 在将参数传递给基类时使用 std::move()