Memcpy实现,严格别名

在学习c的同时,我实现了自己的memcpyfunction。 我在函数中使用了更宽泛的类型( 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]; } 

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

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

我试图通过一个联盟进行一些投射,但结果certificate它也是无效的。

如何用更广泛的类型实现这样的function而不破坏严格的别名规则?

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

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

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

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

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

如果您正在使用一个好的C实现,您可能会发现memcpy4四字节复制实现的效果不如本机memcpy ,具体取决于具体情况。

除了假设sizeof(uint32_t) == 4 ,该行

 size /= 4; 

在你的第一个实现是完全错误的:

除法是整数除法,因此它有效地计算floor(size/4) 。 因此,如果原始size不能被4整除,则源中的1到3个字节将不会被复制到目标。