读书人

请帮忙解释一下这个用memcpy的程序解决

发布时间: 2013-07-23 09:43:37 作者: rapoo

请帮忙解释一下这个用memcpy的程序
这个程序用了memcpy得到的结果是
0 1072693248 0 1073741824 0 1074266112 0 1074790400 0 1075052544
Press any key to continue

书上的解释是“memcpy不知道也不关心数据类型;它只是把一些字节从一个位置复制到另一个位置。复制过程也不进行数据转抽象换。如果使用循环对元素逐个赋值,那么在赋值过程中会将double类型转换成int类型值。此时,对字节按原样进行复制,然后程序把数据作为int类型进行解释。”

我对这段话的理解是memcpy 不能在不同类型的数据间复制。对吗?

#include "stdafx.h"
#include "stdio.h"
#include "string.h"
#include "stdlib.h"

int main(void)
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
double b[5] = {1.0, 2.0, 3.0, 4.0, 5.0};

memcpy(a, b, 5*sizeof(double));
for(int i=0; i<10; i++)
{
printf("%d ", a[i]);
}
putchar('\n');

return 0;
}

[解决办法]
memcpy可以在不同类型的数据间进行复制,只不过对于memcpy函数来讲,它只不过是老老实实的一个字节一个字节的如实拷贝,至于这些字节数据代表的是什么意思,它是不管的,需要程序员自己去掌控。
[解决办法]
00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40 00
00 00 00 00 00 08 40 00 00 00 00 00 00 10 40 00 00
00 00 00 00 14 40

这是doble数组在内存中的表示
memcpy只是把一些字节从一个位置复制到另一个位置。
所以memcpy之后数组a的内存中也是这个
a[0] = 0:00 00 00 00
a[1] = 1072693248 : 00 00 f0 3f


[解决办法]
看内存,理解各类型在内存中的存储方式(补码)

设断点,调试,调试中看内存
[解决办法]
你这样只是把内存中五个double的值复制给了10个int,得到一堆至少对于你这个程序来说的垃圾数据。
你这么搞是什么意思。。
另外在memcpy眼中不存在数据类型这个概念,他只是得到两个地址和复制多少字节,如果你要在不同类中复制,还要保证数据有意义,那么你就要做类型转换。
[解决办法]
引用:
...
另外,我还想问,如果a 不是10个数,而且a[20],我只是赋值了前10个数,后面自然就是0了。那么复制double[5]后是全部覆盖了a[20]在80个字节,还是只覆盖了前40个字节,因为double[5]只有40个字节。我验证了下,好像是全部覆盖了。得到的结果是:



0 1072693248 0 1073741824 0 1074266112 0 1074790400 0 1075052544
Press any key to continue

...


没看懂你什么意思,请贴代码。。

不同类型的复制有没有意义要看你做什么,你把直接把double复制给int想得到类似4.0变4,3.3变3这样的肯定是不可能的,因为double和int在内存中的存储方式本质上都不一样。
而有时候不同类型间的复制还是有意义的,比如char和int间的复制,因为整数在内存中的存储方式本质是一样的,所以假如有一个为200的char复制给int,还是可以保证得到200,而不是其他垃圾数据。

如果你不了解各种类型在内存中是怎么存储的,那光看内存也没用,建议你先去了解一下整数和浮点数在内存中的存储方式,懂了以后你再来看你现在的问题,绝对瞬间理解了。
[解决办法]
给你写段测试代码,目的就是说明一点memcpy是单字节拷贝,不管你是啥数据类型!

lz的问题是纠结于下半句了“如果使用循环对元素逐个赋值,那么在赋值过程中会将double类型转换成int类型值。此时,对字节按原样进行复制,然后程序把数据作为int类型进行解释。”这个说的是强制类型转换中的处理措施!



/*
*void * memcpy ( void * destination, const void * source, size_t num );

Copy block of memory
Copies the values of num bytes from the location pointed by source
directly to the memory block pointed by destination.

The underlying type of the objects pointed by both the source and destination
pointers are irrelevant for this function; The result is a binary copy of the data.

The function does not check for any terminating null character in source - it
always copies exactly num bytes.

To avoid overflows, the size of the arrays pointed by both the destination and
source parameters, shall be at least num bytes, and should not overlap
(for overlapping memory blocks, memmove is a safer approach).
*/
#include <stdio.h>
#include <string.h>

void get_byte(void *s, void *d, size_t size)
{
/* -----------------------------
*
[解决办法]
0
[解决办法]
1
[解决办法]
2
[解决办法]
3
[解决办法]

* -----------------------------


*32bit,4byte
*/
asm (
"loop_start:"
"movl (%%esi), %%ebx\n\t"

"bswap %%ebx\n\t"
//获取0
"movl $0, %%edx\n\t"
"movb %%bl, %%dl\n\t"
"movl %%edx, (%%edi)\n\t"
//获取1
"movl $0, %%edx\n\t"
"movb %%bh, %%dl\n\t"
"movl %%edx, 4(%%edi)\n\t"

"bswap %%ebx\n\t"
//获取2
"movl $0, %%edx\n\t"
"movb %%bh, %%dl\n\t"
"movl %%edx, 8(%%edi)\n\t"
//获取3
"movl $0, %%edx\n\t"
"movb %%bl, %%dl\n\t"
"movl %%edx, 12(%%edi)\n\t"
"addl $4, %%esi\n\t"
"addl $16, %%edi\n\t"
"loop loop_start\n\t"
:
:"S"(s),"D"(d),"c"(size));
}
void get_byte_2(int *s, int *d, size_t size)
{
int i, j;
for(i = 0; i < size; ++i)
{
for(j = 0; j < 4; ++j)
{
*(d + 4 * i + j) = (*s >> (8 * j)) & 0xff;
}
}
}

int main(void)
{
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, a_byte[40] = {0}, b_byte[40] = {0};
double b[5] = {1.0, 2.0, 3.0, 4.0, 5.0};
int i = 0, j = 0;
void *p = b, *q = p + 1;
//上面给出两中方法,效果一样的,但是做法不一样!选择一个即可
//获取b各变量的字节值,和复制后做比较
get_byte(b, b_byte, 10);//按32位处理,故传入10

//获取a各个变量的字节值
get_byte(a, a_byte, 10);

//测试a的字节和b的字节关系
for(i = 0; i < 40; ++i)
{
if(*(a_byte + i) != *(b_byte + i))
break;
}
if(i == 40)
printf("equal!\n");
else
printf("unequal!\n");

//字节拷贝
memcpy(a, b, 40);

//重新获取a的各字节值
get_byte(a, a_byte, 10);

//再测试ab的关系
for(i = 0; i < 40; ++i)
{
if(*(a_byte + i) != *(b_byte + i))
break;
}
if(i == 40)
printf("equal!\n");
else
printf("unequal!\n");

return 0;
}

读书人网 >C语言

热点推荐