一个选择题
数组data最终的数据是哪个()。#define MAX_DATA_SIZE (10)
int main()
{
unsigned int i = 0;
unsigned char data = { '1','2','3','4','5','6','7','8','9','0' };
memcpy(&data, data, MAX_DATA_SIZE / 2);
return 0;
}
1234567890
1212121890
1212345890
其他结果都不对
KEY:C???
不应该是B、1212121890吗??
拷贝过来data里的数据就应该变了呀?? 我们以1212345890为例,具体看一看memcpy内部是怎么做的(在vs2017中)
通过分析memcpy的源代码,我发现vs是先复制后4个字节,然后再复制最前面那1个字节
先把 复制到 (一次性复制4个字节)
最后把复制到
如果你有能力研究memcpy的源代码,那么请看下面的memcpy源代码,如果没有能力研究,那么目前你只是记住“不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同的结果”就行了,等你有了这个能力以后,自己去看源代码
page ,132
title memcpy - Copy source memory bytes to destination
;***
;memcpy.asm - contains memcpy and memmove routines
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;Purpose:
; memcpy() copies a source memory buffer to a destination buffer.
; Overlapping buffers are not treated specially, so propogation may occur.
; memmove() copies a source memory buffer to a destination buffer.
; Overlapping buffers are treated specially, to avoid propogation.
;
;*******************************************************************************
.xlist
include vcruntime.inc
.list
.xmm
M_EXITmacro
ret ; _cdecl return
endm ; M_EXIT
PALIGN_memcpy macro d
MovPalign&d&:
movdqaxmm1,xmmword ptr
lea esi, byte ptr
align @WordSize
PalignLoop&d&:
movdqaxmm3,xmmword ptr
sub ecx,30h
movdqaxmm0,xmmword ptr
movdqaxmm5,xmmword ptr
lea esi, xmmword ptr
cmp ecx,30h
movdqaxmm2,xmm3
palignr xmm3,xmm1,d
movdqaxmmword ptr ,xmm3
movdqaxmm4,xmm0
palignr xmm0,xmm2,d
movdqaxmmword ptr ,xmm0
movdqaxmm1,xmm5
palignr xmm5,xmm4,d
movdqaxmmword ptr ,xmm5
lea edi, xmmword ptr
jae PalignLoop&d&
lea esi, xmmword ptr
endm ; PALIGN_memcpy
CODESEG
extrn __isa_available:dword
extrn __isa_enabled:dword
extrn __favor:dword
page
;***
;memcpy - Copy source buffer to destination buffer
;
;Purpose:
; memcpy() copies a source memory buffer to a destination memory buffer.
; This routine does NOT recognize overlapping buffers, and thus can lead
; to propogation.
; For cases where propogation must be avoided, memmove() must be used.
;
; Algorithm:
;
; Same as memmove. See Below
;
;
;memmove - Copy source buffer to destination buffer
;
;Purpose:
; memmove() copies a source memory buffer to a destination memory buffer.
; This routine recognize overlapping buffers to avoid propogation.
; For cases where propogation is not a problem, memcpy() can be used.
;
; Algorithm:
;
; void * memmove(void * dst, void * src, size_t count)
; {
; void * ret = dst;
;
; if (dst <= src || dst >= (src + count)) {
; /*
; * Non-Overlapping Buffers
; * copy from lower addresses to higher addresses
; */
; while (count--)
; *dst++ = *src++;
; }
; else {
; /*
; * Overlapping Buffers
; * copy from higher addresses to lower addresses
; */
; dst += count - 1;
; src += count - 1;
;
; while (count--)
; *dst-- = *src--;
; }
;
; return(ret);
; }
;
;
;Entry:
; void *dst = pointer to destination buffer
; const void *src = pointer to source buffer
; size_t count = number of bytes to copy
;
;Exit:
; Returns a pointer to the destination buffer in AX/DX:AX
;
;Uses:
; CX, DX
;
;Exceptions:
;*******************************************************************************
ifdef MEM_MOVE
_MEM_ equ <memmove>
else; MEM_MOVE
_MEM_ equ <memcpy>
endif; MEM_MOVE
% public_MEM_
_MEM_ proc \
dst:ptr byte, \
src:ptr byte, \
count:IWORD
; destination pointer
; source pointer
; number of bytes to copy
OPTION PROLOGUE:NONE, EPILOGUE:NONE
push edi ; save edi
push esi ; save esi
; size param/4 prolog byte#reg saved
.FPO ( 0, 3 , $-_MEM_ , 2, 0, 0 )
mov esi, ; esi = source
mov ecx, ; ecx = number of bytes to move
mov edi, ; edi = dest
;
; Check for overlapping buffers:
; If (dst <= src) Or (dst >= src + Count) Then
; Do normal (Upwards) Copy
; Else
; Do Downwards Copy to avoid propagation
;
mov eax,ecx ; eax = byte count
mov edx,ecx ; edx = byte count
add eax,esi ; eax = point past source end
cmp edi,esi ; dst <= src ?
jbe short CopyUp ; no overlap: copy toward higher addresses
cmp edi,eax ; dst < (src + count) ?
jb CopyDown ; overlap: copy toward lower addresses
;
; Buffers do not overlap, copy toward higher addresses.
;
CopyUp:
cmp ecx, 020h
jb CopyUpDwordMov ; size smaller than 32 bytes, use dwords
cmp ecx, 080h
jae CopyUpLargeMov ; if greater than or equal to 128 bytes, use Enhanced fast Strings
bt __isa_enabled, __ISA_AVAILABLE_SSE2
jc XmmCopySmallTest
jmp Dword_align
CopyUpLargeMov:
bt __favor, __FAVOR_ENFSTRG ; check if Enhanced Fast Strings is supported
jnc CopyUpSSE2Check ; if not, check for SSE2 support
rep movsb
mov eax, ; return original destination pointer
pop esi
pop edi
M_EXIT
;
; Check if source and destination are equally aligned.
;
CopyUpSSE2Check:
mov eax,edi
xor eax,esi
test eax,15
jne AtomChk ; Not aligned go check Atom
bt __isa_enabled, __ISA_AVAILABLE_SSE2
jc XmmCopy ; yes, go SSE2 copy (params already set)
AtomChk:
; Is Atom supported?
bt __favor, __FAVOR_ATOM
jnc Dword_align ; no,jump
; check if dst is 4 byte aligned
test edi, 3
jne Dword_align
; check if src is 4 byte aligned
test esi, 3
jne Dword_align_Ok
; A software pipelining vectorized memcpy loop using PALIGN instructions
; (1) copy the first bytes to align dst up to the nearest 16-byte boundary
; 4 byte align -> 12 byte copy, 8 byte align -> 8 byte copy, 12 byte align -> 4 byte copy
PalignHead4:
bt edi, 2
jae PalignHead8
mov eax, dword ptr
sub ecx, 4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
PalignHead8:
bt edi, 3
jae PalignLoop
movq xmm1, qword ptr
sub ecx, 8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
;(2) Use SSE palign loop
PalignLoop:
test esi, 7
je MovPalign8
bt esi, 3
jae MovPalign4
PALIGN_memcpy 12
jmp PalignTail
PALIGN_memcpy 8
jmp PalignTail
PALIGN_memcpy 4
;(3) Copy the tailing bytes.
PalignTail:
cmp ecx,10h
jb PalignTail4
movdqu xmm1,xmmword ptr
sub ecx, 10h
lea esi, xmmword ptr
movdqa xmmword ptr ,xmm1
lea edi, xmmword ptr
jmp PalignTail
PalignTail4:
bt ecx, 2
jae PalignTail8
mov eax, dword ptr
sub ecx,4
lea esi, byte ptr
mov dword ptr , eax
lea edi, byte ptr
PalignTail8:
bt ecx, 3
jae PalignTailLE3
movq xmm1, qword ptr
sub ecx,8
lea esi, byte ptr
movq qword ptr , xmm1
lea edi, byte ptr
PalignTailLE3:
mov eax, dword ptr TrailingUpVec
jmp eax
; The algorithm for forward moves is to align the destination to a dword
; boundary and so we can move dwords with an aligned destination.This
; occurs in 3 steps.
;
; - move x = ((4 - Dest & 3) & 3) bytes
; - move y = ((L-x) >> 2) dwords
; - move (L - x - y*4) bytes
;
Dword_align:
test edi,11b ; check if destination is dword aligned
jz short Dword_align_Ok ; if destination not dword aligned already, it should be aligned
Dword_up_align_loop:
mov al, byte ptr
mov byte ptr , al
dec ecx
add esi, 1
add edi, 1
test edi, 11b
jnz Dword_up_align_loop
Dword_align_Ok:
mov edx, ecx
cmp ecx, 32
jb CopyUpDwordMov
shr ecx,2
rep movsd ; move all of our dwords
and edx,11b ; trailing byte count
jmp dword ptr TrailingUpVec; process trailing bytes
;
; Code to do optimal memory copies for non-dword-aligned destinations.
;
; The following length check is done for two reasons:
;
; 1. to ensure that the actual move length is greater than any possiale
; alignment move, and
;
; 2. to skip the multiple move logic for small moves where it would
; be faster to move the bytes with one instruction.
;
align @WordSize
ByteCopyUp:
jmp dword ptr TrailingUpVec; process just bytes
;-----------------------------------------------------------------------------
align @WordSize
TrailingUpVec dd TrailingUp0, TrailingUp1, TrailingUp2, TrailingUp3
align @WordSize
TrailingUp0:
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
; spare
M_EXIT
align @WordSize
TrailingUp1:
mov al, ; get byte from source
; spare
mov ,al ; put byte in destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
align @WordSize
TrailingUp2:
mov al, ; get first byte from source
; spare
mov ,al ; put first byte into destination
mov al, ; get second byte from source
mov ,al ; put second byte into destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
align @WordSize
TrailingUp3:
mov al, ; get first byte from source
; spare
mov ,al ; put first byte into destination
mov al, ; get second byte from source
mov ,al ; put second byte into destination
mov al, ; get third byte from source
mov ,al ; put third byte into destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; Copy down to avoid propogation in overlapping buffers.
align @WordSize
CopyDown:
; inserting check for size. For < 16 bytes, use dwords without checkign for alignment
lea esi, ; esi, edi pointing to the end of the buffer
lea edi,
cmp ecx, 32
jb CopyDownSmall
bt __isa_enabled, __ISA_AVAILABLE_SSE2
jc XmmMovLargeAlignTest
; See if the destination start is dword aligned
test edi,11b ; Test if dword aligned
jz CopyDownAligned ; If not, jump
CopyDownNotAligned:
mov edx,edi ; get destination offset
and edx, 11b
sub ecx, edx
CopyDownAlignLoop:
mov al, byte ptr
mov byte ptr, al
dec esi
dec edi
sub edx, 1
jnz CopyDownAlignLoop
CopyDownAligned:
cmp ecx,32 ; test if small enough for unwind copy
jb CopyDownSmall ; if so, then jump
mov edx, ecx
shr ecx,2 ; shift down to dword count
and edx,11b ; trailing byte count
sub esi, 4
sub edi, 4 ; settign up src, dest registers
std ; set direction flag
rep movsd ; move all of dwords at once
cld ; clear direction flag back
jmp dword ptr TrailingDownVec; process trailing bytes
;-----------------------------------------------------------------------------
align @WordSize
TrailingDownVec dd TrailingDown0, TrailingDown1, TrailingDown2, TrailingDown3
align @WordSize
TrailingDown0:
mov eax, ; return original destination pointer
; spare
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
align @WordSize
TrailingDown1:
mov al, ; get byte from source
; spare
mov ,al ; put byte in destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
align @WordSize
TrailingDown2:
mov al, ; get first byte from source
; spare
mov ,al ; put first byte into destination
mov al, ; get second byte from source
mov ,al ; put second byte into destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
align @WordSize
TrailingDown3:
mov al, ; get first byte from source
; spare
mov ,al ; put first byte into destination
mov al, ; get second byte from source
mov ,al ; put second byte into destination
mov al, ; get third byte from source
mov ,al ; put third byte into destination
mov eax, ; return original destination pointer
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
; Copy overlapping buffers using XMM registers
XmmMovLargeAlignTest:
test edi, 0Fh ; check if it's 16-byte aligned
jz XmmMovLargeLoop
XmmMovAlignLoop:
dec ecx
dec esi
dec edi
mov al,
mov , al
test edi, 0Fh
jnz XmmMovAlignLoop
XmmMovLargeLoop:
cmp ecx, 128
jb XmmMovSmallTest
sub esi, 128
sub edi, 128
movdqu xmm0, xmmword ptr
movdqu xmm1, xmmword ptr
movdqu xmm2, xmmword ptr
movdqu xmm3, xmmword ptr
movdqu xmm4, xmmword ptr
movdqu xmm5, xmmword ptr
movdqu xmm6, xmmword ptr
movdqu xmm7, xmmword ptr
movdqu xmmword ptr, xmm0
movdqu xmmword ptr, xmm1
movdqu xmmword ptr, xmm2
movdqu xmmword ptr, xmm3
movdqu xmmword ptr, xmm4
movdqu xmmword ptr, xmm5
movdqu xmmword ptr, xmm6
movdqu xmmword ptr, xmm7
sub ecx, 128
test ecx, 0FFFFFF80h
jnz XmmMovLargeLoop
XmmMovSmallTest:
cmp ecx, 32 ; if lesser than 32, use dwords
jb CopyDownSmall
XmmMovSmallLoop:
sub esi, 32
sub edi, 32
movdqu xmm0, xmmword ptr
movdqu xmm1, xmmword ptr
movdqu xmmword ptr, xmm0
movdqu xmmword ptr, xmm1
sub ecx, 32
test ecx, 0FFFFFFE0h
jnz XmmMovSmallLoop
CopyDownSmall:
test ecx, 0FFFFFFFCh ; mask the bytes
jz CopyDownByteTest
CopyDownDwordLoop:
sub edi, 4
sub esi, 4
mov eax,
mov , eax
sub ecx, 4
test ecx, 0FFFFFFFCh
jnz CopyDownDwordLoop
CopyDownByteTest:
test ecx, ecx
jz CopyDownReturn
CopyDownByteLoop:
sub edi, 1
sub esi, 1
mov al,
mov , al
sub ecx, 1
jnz CopyDownByteLoop
CopyDownReturn:
mov eax, ; return original destination pointer
; spare
pop esi ; restore esi
pop edi ; restore edi
M_EXIT
; Using XMM registers for non-overlapping buffers
align 16
XmmCopy:
mov eax, esi
and eax, 0Fh
; eax = src and dst alignment (src mod 16)
test eax, eax
jne XmmCopyUnaligned
; in:
; edi = dst (16 byte aligned)
; esi = src (16 byte aligned)
; ecx = len is >= (128 - head alignment bytes)
; do block copy using SSE2 stores
XmmCopyAligned:
mov edx, ecx
and ecx, 7Fh
shr edx, 7
je XmmCopySmallTest
; ecx = loop count
; edx = remaining copy length
; Copy greater than or equal to 128 bytes using XMM registers
align 16
XmmCopyLargeLoop:
movdqa xmm0,xmmword ptr
movdqa xmm1,xmmword ptr
movdqa xmm2,xmmword ptr
movdqa xmm3,xmmword ptr
movdqa xmmword ptr ,xmm0
movdqa xmmword ptr ,xmm1
movdqa xmmword ptr ,xmm2
movdqa xmmword ptr ,xmm3
movdqa xmm4,xmmword ptr
movdqa xmm5,xmmword ptr
movdqa xmm6,xmmword ptr
movdqa xmm7,xmmword ptr
movdqa xmmword ptr ,xmm4
movdqa xmmword ptr ,xmm5
movdqa xmmword ptr ,xmm6
movdqa xmmword ptr ,xmm7
lea esi,
lea edi,
dec edx
jne XmmCopyLargeLoop
; Copy lesser than 128 bytes
XmmCopySmallTest:
test ecx, ecx
je CopyUpReturn
; ecx = length (< 128 bytes)
mov edx, ecx
shr edx, 5 ; check if there are 32 bytes that can be set
test edx, edx
je CopyUpDwordMov
; if > 16 bytes do a loop (16 bytes at a time)
; edx - loop count
; edi = dst
; esi = src
align 16
XmmCopySmallLoop:
movdqu xmm0, xmmword ptr
movdqu xmm1, xmmword ptr
movdqu xmmword ptr , xmm0
movdqu xmmword ptr , xmm1
lea esi,
lea edi,
dec edx
jne XmmCopySmallLoop
CopyUpDwordMov:
; last 1-32 bytes: step back according to dst and src alignment and do a 16-byte copy
; esi = src
; eax = src alignment(set at the start of the procedure and preserved up to here)
; edi = dst
; ecx = remaining len
and ecx, 1Fh
je CopyUpReturn
CopyUpDwordTest:
mov eax, ecx; save remaining len and calc number of dwords
shr ecx, 2
je CopyUpByteTest ; if none try bytes
CopyUpDwordLoop:
mov edx, dword ptr
mov dword ptr , edx
add edi, 4
add esi, 4
sub ecx, 1
jne CopyUpDwordLoop
CopyUpByteTest:
mov ecx, eax
and ecx, 03h
je CopyUpReturn ; if none return
CopyUpByteLoop:
mov al, byte ptr
mov byte ptr , al
inc esi
inc edi
dec ecx
jne CopyUpByteLoop
align 16
CopyUpReturn:
; return dst
mov eax, ; return original destination pointer
pop esi
pop edi
M_EXIT
; dst addr is not 16 byte aligned
align 16
XmmCopyUnaligned:
; copy the first the first 1-15 bytes to align both src and dst up to the nearest 16-byte boundary:
; in
; esi = src
; edi = dst
; eax = src and dst alignment
; ecx = length
mov edx, 010h
sub edx, eax ; calculate number of bytes to get it aligned
sub ecx, edx ; calc new length and save it
push ecx
mov eax, edx ; save alignment byte count for dwords
mov ecx, eax ; set ecx to rep count
and ecx, 03h
je XmmAlignDwordTest ; if no bytes go do dwords
XmmAlignByte:
mov dl, byte ptr ; move the bytes
mov byte ptr , dl
inc esi ; incrementthe addresses
inc edi
dec ecx ; decrement the counter
jne XmmAlignByte
XmmAlignDwordTest:
shr eax, 2 ; get dword count
je XmmAlignAdjustCnt ; if none go to main loop
XmmAlignDwordLoop:
mov edx, dword ptr ; move the dwords
mov dword ptr , edx
lea esi, ; increment the addresses
lea edi,
dec eax ; decrement the counter
jne XmmAlignDwordLoop
XmmAlignAdjustCnt:
pop ecx ; retrieve the adjusted length
jmp XmmCopyAligned
_MEM_ endp
end
本帖最后由 82457097 于 2019-4-3 19:11 编辑
memcpy函数第一个参数是指向用来存储复制来的数据的地址的指针;第二个参数是指向赋值源的指针;第三个是复制数据的字节数;
如题:取原数组的第三个元素的地址为储存容器起始地址,取原数组第一个元素地址为复制数据源起始地址,尺寸为5个字节
综上,将3 4 5 6 7改为 1 2 3 4 5 所以得到1 2 1 2 3 4 5 8 9 0; 82457097 发表于 2019-4-3 19:09
memcpy函数第一个参数是指向用来存储复制来的数据的地址的指针;第二个参数是指向赋值源的指针;第三个是复 ...
是把后面5个字节的全部存储下来拷贝过去的吗??不是一个一个拷贝过去的吗??
data = data;
data = data; //12 12 3456
data = data;//这里data不是已经变成1了吗 因为src和dst所指的内存区域重叠了
标准好像并没有规定在这个情况下memcpy的行为
不同的编译器有不同的方法,甚至同一个编译器的不同编译选项都有不同的结果
sh-5.0$ cat main.c
#include <stdio.h>
#include <string.h>
#define MAX_DATA_SIZE (10)
int main()
{
unsigned int i = 0;
unsigned char data = { '1','2','3','4','5','6','7','8','9','0' };
memcpy(&data, data, MAX_DATA_SIZE / 2);
for(i = 0; i < 10; ++i)
{
printf("%c ", data);
}
printf("\n");
return 0;
}
sh-5.0$ gcc -o main main.c
sh-5.0$ ./main
1 2 1 2 3 4 5 8 9 0
sh-5.0$ gcc -O3 -o main main.c
sh-5.0$ ./main
1 2 1 2 3 4 3 8 9 0
sh-5.0$
页:
[1]