欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

char 和 unsigned char 的区别

程序员文章站 2022-05-27 08:36:32
...

一.基本原理

1、char取值范围是 -128~+127。

2、我们先来看 signed char的最大值。  

最高位是 符号位, 0 代表正数; 1 代表负数。0 1 1 1  1 1 1 1     这个值等于 2^0 + 2^1 + 2^2  + 2^3  + 2^4  + 2^5  + 2^6  = 127  。 也有一个简便计算方法:2^7 -1 = 128-1 =127   所以,signed char 的最大值是 127 。

singed char 的最小值计算。 在计算机中,数值是以补码形式存储的。正数的补码是其本身; 而负数的补码是 取反 (符号位保持不变),再加1。

我们先来看 -1 的存储过程:

-1: 1 0 0 0 0 0 0 1 ->(取反) 1 1 1 1 1 1 1 0 ->(加1) 1 1 1 1 1 1 1 1

-2: 1 0 0 0 0 0 1 0 ->(取反) 1 1 1 1 1 1 0 1 ->(加1) 1 1 1 1 1 1 1 0

-3: 1 0 0 0 0 0 1 1 ->(取反) 1 1 1 1 1 1 0 0 ->(加1) 1 1 1 1 1 1 0 1

… …

-127 1 1 1 1 1 1 1 1 ->(取反) 1 0 0 0 0 0 0 0 ->(加1) 1 0 0 0 0 0 0 1

-128 1 0 0 0 0 0 0 0 ->(取反) 1 1 1 1 1 1 1 1 ->(加1) 1 0 0 0 0 0 0 0

不管是原码还是补码, 总会出现 -0 这个值。 本来 +0 与 -0 是没有区别的。 但对于存储器和编译器来讲,总得充分利用每个字节吧, 更不想出现二义性。 所以,将 -0 表示为 -128 , 这样既增大了signed char 数值的表示范围,又消除了 -0 的二义性。

所以signed char的取值范围是 -128~127。

3.unsigned char没有符号位  最大值是  255(1 1 1 1 1 1 1 1)

我们看下下面的代码测试程序,就会清晰很多了

#include<iostream>
using namespace std;
int main(int argc, char * argv[])
{
	//正数在计算机中存储的是源码,而负数存储的是补码
	//在赋值的过程中,就是把计算机中存储的内容直接赋给对应的变量
	//只是有符号数直接会把他当成补码处理,再对其进行减一取反操作
	//至少在我这里是这样的看的。然后看他的符号位。
	//没符号的数  就会直接按照源码处理,因为没有符号位,直接翻译过来。


	//对于负数计算机存储的是补码,而对于正数计算机存储的是源码
	char a = 0x81;
	/*
	//这里就匹配不上了,因为0x81 在计算机存储的是源码 1 0 0 0 0 0 0 1
	而赋值给一个有符号的char 会当作补码进行处理,先对其减一
	1 0 0 0 0 0 0 0,再对除符号位外进行取反。
	1 1 1 1 1 1 1 1,
	然后得到解析数值 -127,显然-127和+129显然是不相等的。
	这里同时要注意在a的地址里存储的还是  10000001,只是把这个解析成补码了

	*/
	if (a == 0x81)
	{
		printf("you are matched!!!\n");
	}
	
	printf("a is %d\n", a);
	//对其赋值给 unsigned char的时候,是会直接把a中在内存中存储的值
	//10000001,而赋值给 unsigned char之后,unsigned char之后会当
	//源码进行解析,则又恢复了原来的129.
	unsigned char w = a;
	printf("w is %d\n", w);

	/*
	-1 在计算机中按照补码存储  存储的数值是 11111111
	把这个值赋值给一个 unsigned char 之后就会按照源码处理
	没有符号位翻译成了 255
	*/
	char testc = -1;
	unsigned char test_uc = testc;
	printf("test_uc =%d\n", test_uc);
	return 0;
}

输出内容如下:

a is -127
w is 129
test_uc =255

二.printf 输出的影响

在C中,默认的基础数据类型均为signed,如定义变量为int,long等,都为有符号的。如果要定义无符号类型,必须显式地在变量类型前加unsigned。

char vs unsigned char
相同点:在内存中都是一个字节,8位(2^8=256),都能表示256个数字
不同点:char的最高位为符号位,因此char能表示的数据范围是-128~127,unsigned char没有符号位,因此能表示的数据范围是0~255

实际使用中,如普通的赋值,读写文件和网络字节流都没有区别,不管最高位是什么,最终的读取结果都一样,在屏幕上面的显示可能不一样。

但是要把一个char类型的变量赋值给int、long等数据类型或进行类似的强制类型转换时时,系统会进行类型扩展,这时区别就大了。对于char类型的变量,系统会认为最高位为符号位,然后对最高位进行扩展,即符号扩展。若最高位为1,则扩展到int时高位都以1填充对于unsigned char类型的变量,系统会直接进行无符号扩展,即0扩展。扩展的高位都以0填充。所以在进行类似的操作时,如果char和unsigned char最高位都是0,则结果是一样的,若char最高位为1,则结果会大相径庭。

#include <stdio.h>
/*
%d,%c,%s,%x是程序汇编语言中的格式符,它们的含义:

1、%d表示按整型数据的实际长度输出数据。//不会进行扩展到四个字节

2、%c用来输出一个字符。就输出一个字节里的内容,然后得到数值,不关心符号位,直接把对应的二进制变成一个正数
//找对应的acs码符号
3、%x表示以十六进制数形式输出整数。
//会扩展到四个字节 char类型的负数赋值给他影响较大,
所有高位都会扩展为1,其他位都不变(包括原来的符号位)
这个一般的办法是把高位清零来看,就是与0xff想与

4、%u表示以无符号十进制整数形式输出整数。
//会扩展到四个四节
char类型的负数赋值给他影响较大,
所有高位都会扩展为1,其他位都不变(包括原来的符号位)


*/
static void func(unsigned char uc)
{
	char c;
	int i, j;
	unsigned int ui, uj;

	c = uc;
	i = (int)c;
	j = (int)uc;
	ui = (unsigned int)c;
	uj = (unsigned int)uc;
	printf("%%d: %d, %d\n", c, uc);//-128,  //128
	printf("%%c: %c, %c\n", c, uc);//直接输出二进制对应的数值
	printf("%%x: %x, %x\n", c, uc);//-80   //)0X80
	printf("%%u: %u, %u\n", ui, uj);//128     //128
	printf("%%d: %d, %d\n", i, j);//-128    //128
	printf("-------------------\n");
}

int main(int argc, char *argv[])
{
	func(0x80);
	func(0x7f);
	int a = -2;
	printf("a is :\n %%x:%x\n %%d:%d \n %%u:%u \n", a,a,a);
	return 0;
}


输出结果如下:

char 和 unsigned char 的区别

暂时总结到这里

相关标签: C/C++