在学习 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/