C/C++ 语言 零碎知识点的总结(2)干货

  C/C++ 语言 零碎知识点的总结(2)

  在大三的有限时间中对自己所遇到过的C/C++知识点做学习记录,以便在自己遗忘之时回顾。

  若有朋友想了解其他知识点,传送门:C/C++ 语言 零碎知识点的总结 (1)

  首先,来观察下面一段简单的代码:

	# include
	
	int main( int argc,char *argv[] ) {
     
	
		printf("%d",(unsigned char)-1);
		
		return 0;
}

  博主就开门见山了,运行结果:255
C/C++ 语言 零碎知识点的总结(2)干货_第1张图片
  或许会有朋友迷糊了,答案不应该是“-1”么?别急,博主这就为你慢慢解答。
  为了具体而又明确的解答该问题,我们需要引入概念: 对C/C++中 char类型数据 做一个新的学习和了解。

  C/C++语言中的char类型数据

  美国国家标准协会(ANSI)对char的定义是unsigned类型,而不像int/long/short等类型的数据即使不指定signed/unsigned时默认也为signed,这也使得char在C/C++的整型数据中显得最为独特的一个。

  ANSI C 提供了3种字符类型: char、signed char、unsigned char,三者均占1个字节(1字节8bit)。
  unsigned char,char类型变量的大小通常为1个字节(1字节=8个位),且属于整型。整型的每一种都有无符号(unsigned)和有符号(signed)两种类型(float和double总是带符号的),在默认情况下声明的整型变量都是有符号的类型(char有点特别),如果需要声明无符号类型时就用unsigned关键字对其声明。无符号版本和有符号版本的区别就是无符号类型能保存2倍有符号类型的数据,比如 16位系统中一个int能存储的数据的范围为-32768~32767,而unsigned能存储的数据范围则是0~65535。
  char类型一般为1个字节即8个bit(无论32位或 64位操作系统),所以能存储的数据范围为-128~127,而 unsigned char则是0~255,字符型所存储的数据是用来表示字符的,例如ASCⅡ或Unicode 。
  另外,char在标准上虽然被定义为unsigned但具体有无符号是由编译器所决定的,VC编译器、x86char定义为signed char,而ARM-linux-gcc却把char定义为 unsigned char。

  存储:

   数据在计算机中是以二进制补码形式储存的,但为了更好的与人交流,编译器通常会以十六进制形式对其处理。
   例如,-1在内存中实际上是以“11111111111111111111111111111111”的方式存储的,但编译器会在运算时处理为:0xFFFFFFFF(十六进制)
C/C++ 语言 零碎知识点的总结(2)干货_第2张图片
       计算机  补码存储顺序 简图

  类型转换:

  int/unsigned int变量赋值给 unsigned char变量 是会发生字节截断(9位和高于9位的将被程序自动丢弃)。

	unsigned int a = 0xFFFFFFF7;
	unsigned char b = (unsigned char)a;

  此时b的值为 0xF7

  解答:

	printf("%d",(unsigned char)-1);
  通过简单讲解,我们就清楚了,在前面的代码中 -1 是以 “ 0xFFFFFFFF ” 的形式参与运算的,在被 unsigned char 强制转换后,发生了字节截断 的现象,变成 “0xFF” 的十六进制数,再按“%d”十进制输出时,就是255了,也就是char所能表示的最大范围数,你明白了么?

  (Signed)char与unsigned char的区别

  我们先来看如下实例代码:

	# include 
	void f(unsigned char v) {
     /* 若函数修改写为void f(char v){...}时,
								运行效果是一样的,
	因为,在普通的赋值,读写文件和网络字节字节流时char和unsigned char是没有区别的,都一个字节8个bit。*/
	
		char c=v;
		unsigned char uc = v;
		
		unsigned int a =c,b=uc;
		
		int i=c, j=uc;
		
			printf("--------------\n");
			printf("%%c:%c,%c\n",c,uc);
			printf("%%X:%X,%X\n",c,uc);
			printf("%%u:%u,%u\n",a,b);
			printf("%%d:%d,%d\n",i,j);	
			
	}
	
	int main(){
     
	
		f(0x61);
		f(0x7F);
		f(0x80);


		return 0;
	}

  执行结果:

	--------------
	%c:a,a
	%X:61,61
	%u:97,97
	%d:97,97
	--------------
	%c:,
	%X:7F,7F
	%u:127,127
	%d:127,127
	--------------
	%c:�,�
	%X:FFFFFF80,80
	%u:4294967168,128
	%d:-128,128

C/C++ 语言 零碎知识点的总结(2)干货_第3张图片

  做为初学者,可能会对该代码的运行结果感到困惑,为什么会有如此结果呢?别急,帅气又友善的博主正在为你解答,哈哈哈。

  首先明确,在C语言中char是整数类型(integer type),因为在内存中char是整数二进制补码存储的。计算机用特定整数编码来表示特定的字符,其中最能代表的便是ASCLL码值,ASCLL码的取值范围为:0~127, 也就是说 char在0~127范围内为ACSLL码字符
  注意: 这里0~127是指十进制

  而作为在0~127的数值范围内的字符时,char和unsigontned char是无区别的 !! 这也就很好的理解了,为什么在上述代码中,当传参为 0x610x7F时char和unsigned的运行结果均一样:

0x61的运行结果:
	%c:a,a		
	%X:61,61
	%u:97,97	
	%d:97,97
	
0x7F的运行结果:
	%c:,
	%X:7F,7F
	%u:127,127
	%d:127,127

  由于所给字符数值均在ASCLL码的范围内,所以char和unsigned char是没有区别的,char或unsigned char无论赋值给谁,都为ACSLL码表所对应的值:

	unsigned int a =c,b=uc;	
	int i=c, j=uc;

  所以此时char或unsigned char无论赋值给int或是unsigned int,效果都是一样的,都为ASCLL码。

  不管用何种格式的输出:

		printf("%%c:%c,%c\n",c,uc);
		printf("%%X:%X,%X\n",c,uc);
		printf("%%u:%u,%u\n",a,b);
		printf("%%d:%d,%d\n",i,j);	

  都对应下图表中:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
  查询ASCLL码值表,可以看到"0x61" 0x7F分别是 字符 ‘a’删除字符DEL,且0x7F是字符所能表示的最大值。

  若char的值超出ASCLL码的范围时:

  给函数 f 传入参数 "0x80" ,函数实际上变成了:

	char c='0x80';
	unsigned char uc = '0x80';
	
	unsigned int a =c,b=uc;
	
	int i=c, j=uc;
	
		printf("--------------\n");
		printf("%%c:%c,%c\n",c,uc);
		printf("%%X:%X,%X\n",c,uc);
		printf("%%u:%u,%u\n",a,b);
		printf("%%d:%d,%d\n",i,j);	

  结果:
  ①

	--------------
	%c:�,�	

  由于 "0x80" 超出了ascll码所能表示的最大字符,所以出现了未定义字符:“�” 。
  ②

	%X:FFFFFF80,80
	%u:4294967168,128

  第二、三条输出结果的原因:因为char为signed有符号型字符占1个字节数据,而unsigned int和int是四个字节,当有符号(signed) char低字节的数据给高字节的数unsigned int和int赋值时,会对高位拓展,又因为编译器和系统的预先处理(会以十六进制存储),所以,有符号的char在%X格式输出时会原样输出:FFFFFF80,而十六进制数0xFFFFFF80的十进制为:4294967168
也就是%u格式输出数

  注意: 变量a是unsigned类型的int,所以无论是%u无符号十进制输出还是%d十进制输出,都会是4294967168

  不同的是无符型unsigned char在给高字节数据赋值时,无论何种数据,都不会拓展

  总结
  1. char和unsigned char在ASCLL码范围内是一致的,但当超出ASCLL码值就会发生高位扩展,且均以F填补
  2. 普通的赋值,读写文件和网络字节字节流时char和unsigned char是没有区别的,均是一个字节8个bit

  ③

	%d:-128,128

  为什么变量 i 的 “%d” 输出会是-128呢?相信你已理解前文中存储一块的相关介绍了。由于数据是以十六进制存储的,而十六进制凡以F开头的数,均为负数,也就是说char在高位拓展时就已转成了负数,且int是有符型数据,所以,int i无论以何种进制输出,int i均为负


  感谢各位路过的小可爱们能和博主共同学习进步,今天是周天,博主也在教室中对C/C++中char的知识点断断续续的总结完毕了,期待下次跟大家学习分享。

你可能感兴趣的:(C,语言,C/C++,c语言,c++,后端,编程语言,经验分享)