Ang*_*gus 11 c language-implementation memcpy
我正在寻找memcpy.c的实现,我发现了一个不同的memcpy代码.我无法理解他们为什么这样做(((地址)s)|((ADDRESS)d)| c)&(sizeof(UINT) - 1)
#if !defined(__MACHDEP_MEMFUNC)
#ifdef _MSC_VER
#pragma function(memcpy)
#undef __MEMFUNC_ARE_INLINED
#endif
#if !defined(__MEMFUNC_ARE_INLINED)
/* Copy C bytes from S to D.
* Only works if non-overlapping, or if D < S.
*/
EXTERN_C void * __cdecl memcpy(void *d, const void *s, size_t c)
{
if ((((ADDRESS) s) | ((ADDRESS) d) | c) & (sizeof(UINT) - 1)) {
BYTE *pS = (BYTE *) s;
BYTE *pD = (BYTE *) d;
BYTE *pE = (BYTE *) (((ADDRESS) s) + c);
while (pS != pE)
*(pD++) = *(pS++);
}
else {
UINT *pS = (UINT *) s;
UINT *pD = (UINT *) d;
UINT *pE = (UINT *) (BYTE *) (((ADDRESS) s) + c);
while (pS != pE)
*(pD++) = *(pS++);
}
return d;
}
#endif /* ! __MEMFUNC_ARE_INLINED */
#endif /* ! __MACHDEP_MEMFUNC */
Run Code Online (Sandbox Code Playgroud)
Eri*_*hil 14
代码正在测试地址是否适合于a UINT.如果是,则代码使用UINT对象进行复制.如果不是,则代码使用BYTE对象进行复制.
测试首先执行两个地址的按位OR.任一地址中的任何位都将在结果中打开.然后测试执行按位AND sizeof(UINT) - 1.预计a的大小UINT是2的幂.然后,大小减去1的所有低位都打开.例如,如果大小是4或8,那么小于4,或者是二进制11 2或111 2.如果任一地址不是a的大小的倍数UINT,那么它将打开其中一个位,并且测试将指示它.(通常,整数对象的最佳对齐方式与其大小相同.这不一定正确.应使用此代码的现代实现_Alignof(UINT) - 1而不是大小.)
复制UINT对象更快,因为在硬件级别,一个加载或存储指令加载或存储a的所有字节UINT(可能是四个字节).处理器通常在使用这些指令时比使用四倍数量的单字节加载或存储指令更快地复制.
这段代码当然是依赖于实现的; 它需要来自C实现的支持,它不是基本C标准的一部分,它取决于它执行的处理器的特定功能.
更高级的memcpy实现可以包含其他功能,例如:
Die*_*Epp 13
代码
((((ADDRESS) s) | ((ADDRESS) d) | c) & (sizeof(UINT) - 1))
Run Code Online (Sandbox Code Playgroud)
检查是否任s,d或c不对齐的大小UINT.
例如,如果s = 0x7ff30b14,,d = 0x7ffa81d8c = 256,和sizeof(UINT) == 4,则:
s = 0b1111111111100110000101100010100
d = 0b1111111111110101000000111011000
c = 0b0000000000000000000000100000000
s | d | c = 0b1111111111110111000101111011100
(s | d | c) & 3 = 0b00
Run Code Online (Sandbox Code Playgroud)
所以两个指针都是对齐的.在两个对齐的指针之间复制内存更容易,而这仅使用一个分支.
在很多平台上,*(UINT *) ptr是多快,如果ptr被正确对齐的宽度UINT.在某些体系结构上,*(UINT *) ptr如果ptr未正确对齐,实际上会崩溃.