无聊的时候翻了翻《C标准库》,无意间发现了一个很有意思的问题,就拿来与大家分享分享
我们首先看一下这两个库函数原型:
1、memcpy 函数原型为 :
void *memcpy(void *s1 ,const void * s2 ,size_t n)
{
char *su1;
const char *su2;
for(su1 = s1,su2 = s2;0 < n; ++su1, ++su2, --n)
{
*su1 = *su2;
}
return (s1);
}
2、memset 函数的原型为:
void *memset(void *s,int c,size_t n)
{
const unsigned char uc = c;
unsigned char *su;
for(su = s; 0 < n; ++su, --n)
{
*su = uc;
}
return s;
}
我们发现 这两个函数对内存进行操作时,将内部指针变量一个声明为char型另一个声明为unsigned char 型,到底为什么要这么声明,他们两个类型之间对内存数据的读写到底有什么区别?为了说明他们之间的区别,让我们先看看下面的例子
#include <stdio.h>
#include <string.h>
int main(void)
{
char c = 120;
unsigned char d = 120;
char *pchr;
unsigned char *puchr;
printf("c = %d/n",c);
printf("d = %d/n",d);
pchr = &c;
puchr = (unsigned char *)pchr;
printf("*pchr = %d/n",*pchr);
printf("*puchr = %d/n",*puchr);
return 0;
}
运行结果:
c = 120
d = 120
*pchr = 120
*puchr = 120
我们看到无论char还是 unsigned char型指针对同一内存地址读取一个字节的数据的到值没有任何区别。我们再看一个例子
#include <stdio.h>
#include <string.h>
int main(void)
{
char c = 128;
unsigned char d = 128;
char *pchr;
unsigned char *puchr;
printf("c = %d/n",c);
printf("d = %d/n",d);
pchr = &c;
puchr = (unsigned char *)pchr;
printf("*pchr = %d/n",*pchr);
printf("*puchr = %d/n",*puchr);
return 0;
}
运行结果:
c = -128
d = 128
*pchr = -128
*puchr = 128
我们看到用不同类型的指针变量读取同一内存地址中的数据得到结果却不一样。为什么会得到这样的结果?
我们知道char类型的取值范围为-128--127,因此c = 128溢出,但在内存中存储的数据到底是什么,为什么能够得到-128这个数据呢。
我们先看看-128在内存中存储的二进制数为 (128 原码 1000 0000 反码 0111 1111 补码1000 0000 )1000 0000(-128在内存中是以补码存储的),而又得到 *puchr = 128,因此可推理得到,内存中存储的数据的二进制为 1000 0000 。
因此可得,以下结论:
(1)在计算机数据存储的结论,无论变量的类型是char型还是unsigned char型,对该变量赋值时,存储在变量内存中的二进制的数值取决于等号右边的数值,与变量类型无关。即用 -255-255范围内数,char与 unsigned char 型变量赋相同数值时,他们内存中数据的二进制一模一样。
(2)读取内存中数据的规则,对于同一内存地址中的数据,用不同类型的变量读取时,得到的结果有可能不一样。原因在于,用char变量读取时他将内存中最高位当成符号位,而unsigned char 变量将内存中最高位当成数值。因此就有了对于同一内存地址用不同类型的指针变量读取一个字节数据,但得到的数值不一样的现象。
因此,在对内存数据进行拷贝和赋值时,无论声明成char还是 unsigned char变量或数组,给他们赋相同数值时,变量内存中的二进制数据一模一样,没有任何区别。即memcpy memset 都是对内存进行操作的无论将指针变量声明char还是unsigned char 对数据都没有影响。只要保证第一个变量与第二个变量类型一致就行。