引子:
本来是搜memcpy在拷贝两个数组时两数组下标类型不同的问题,即,若一个数组是很长,其下标用long型,要将此数组的一小段拷贝到另一个数组中,这另一个数组的下标只需要用int型,不确定会不会出问题。
int i;
long j;
unsigned n = 2;
memcpy( &des_buf[i], &ori_buf[j], n*sizeof(des_buf[0]) );
测试代码:
short i = 2;
int j = 65537;
int n = 2;
float des_buf[10] = { 0 };
float ori_buf[100000] = {0};
ori_buf[j] = 0.1;
ori_buf[j+1] = 0.2;
memcpy(&des_buf[i], &ori_buf[j], n * sizeof(des_buf[0]));
des_buf的内存:
是没有问题的,哪怕n的类型是int而不是unsigned int。
问题:
然后搜到:
memcpy,复制内存,但是字节数和参数给定的不一样_百度知道 (baidu.com)
是这个帖子的问题。
看了二楼的答案,试了不行,还是打印一样的结果。
暂时我也还没找到问题在哪,只不过做了一些试验,得到一些结论,先记在这里了。
先将代码改成这样标准点,将value用二进制打印出来,看下其占几个字节,每个字节的值:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
void main()
{
char* des = NULL;
des = (char*)malloc(2);
int value = 0x8547;
char buf[128];
_itoa(value, buf, 2);
printf("二进制: %s\n", buf);
memcpy(des, &value, 2*sizeof(char));
char* test = NULL;
for (test = des; test < des + 2; test++)
{
printf("0x%02X,", *test); // 打印十六进制的ASCII码 两位表示
}
free(des);
}
结果:
分析、测试过程:
二进制值,0x8547,确实是按照字节来转的,即85对应10000101,47对应01000111。
按说,vaule是32位的,即有四个字节,但是这里转化后只有两个字节,认为是最低的两个字节,拷贝时,也是拷贝低两个字节,且,默认数据是按照小端对齐存储,即两个字节在内存中是按照47 85来存的,所以拷贝时,先拷贝47这个字节,再拷贝85这个字节。
对应打印时,先打印47这个字节,再打印85这个字节,顺序是对上的,只是85这个字节打印得不对。
其次,我们来看内存,即拷贝情况:
1、
des申请内存后的值:
前两个字节,是有初值的。
执行memcpy语句后,des值:
可见,两个字节是拷贝成功了,顺序也是对的。
des地址再往前看一点:
前面都是fd 00之类。没有ff之类。
2、
将test指针指向des,看test:
和des一样。往前看一点:
也是一样的,都是fd 00之类。没有ff之类。
3、
打印第一次,即打印第一个字节:
打印第二个字节:
先看内存,此时地址变为:
即地址确实是加了一个字节,按说应该打印85。打印:
打印不对了!
4、做其他尝试
怀疑这个打印值有问题,因为正常0x85值是133,133用有符号的一个字节是表示不了的,即超出表示范围,或者说,int的四个字节,不应该用倒数第二个字节表示0x85,而是要向左再多一位?但是这里貌似每个十六进制字节就是对应二进制8位表示,比如如果value = 0x668547,相应拷贝3个char数据并打印:
可见,value的倒数第三个字节,只会保存字节数据0x66。且,这里打印也是对的。那么,是数值0x85不能正确打印了。将value值改为3587,再走一遍上面1 2 3流程:
des:
test:
打印:
明明是要打印一个字节的87,却打印出4个字节的0Xffffff87.
看des前的字节:
也不是ff这种啊。那么是打印时出错?
第一次打印test前test前的字节:
前面字节也没有ff这种。
test++:
打印:
35这一个字节正常打印。
所以还是打印问题,拷贝应该是没有问题的。
5、但是——直接打印0x87:
加一句打印:
printf("0x%02X,", 0x87);
这里,好像0x87是可以打印的!因为就是一个字节啊......
那么,是偏移地址不对???
看此时的监视窗口:
71即是0x47的十进制值,对应的ASCII码是G。所以打印47是没问题的。然而,此时test指针指向的字节的值,实际是-123,即133-256,因为0x85=133超过128,所以是负值?实际是-123?那么printf按照0x格式打印-123时,就导致打印错误?
直接:printf("0x%02X,", -123);
结果,确实是打印出:
将原程序打印改为十进制:printf("%d,", *test);
结果:
其实就是打印3个字节,且顺序也是对的。所以——
6、最终结论:
是格式转换的问题!要将一个字节数据转换为0x即十六进制时,如果这个字节数据是有符号的,那么可能会出现负值,此时转十六进制会出问题,会打印出前面加3个FF字节,至于为什么是这样加,目前确实还没想明白。