Memcpy实现,严格别名

时间:2014-01-19 13:06:32

标签: 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];
}

我对类型惩罚和严格别名做了一些阅读,我相信上面的功能打破了规则。正确的实现是这样的,因为你可以使用char:

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

我试图通过联盟进行一些投射,但结果证明这也是无效的。

如何使用更宽的类型实现此类函数,而不是破坏严格的别名规则?

1 个答案:

答案 0 :(得分:17)

使用多个单字节副本实现memcpy的方法是使用非标准C。

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

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

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

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

如果您使用的是良好的C实现,您可能会发现-fnostrict-aliasing的四字节副本实现的效果不如原始memcpy4,具体取决于具体情况。