C语言基本数据类型之整型

阅前说明:

本文内容:

整型描述内容包括八进制、十进制、十六进制、short、int、long、long long,以及各自对应的无符号类型。

整型值表示方式:有变量和常量,因规则基本一致有部分被省略,但基本概括全部内容。

用函数integerOverflow(char x);说明整型值的溢出处理;

用函数printIntegerDirect(char x);说明在格式化输出时,用后缀来说明常量类型;

用函数printIntegerTypes(char x);打印所有的常见整型值。

/*C primer plus 第三章C语言基本数据类型3.4.2*/
/*
C语言整型变量的范围、溢出与兼容问题
1. C语言仅仅规定了short的占用的存储空间不多于int,long占用的存储空间不能少于int,这样规定是为了适应不同的机器
	例:in Wins 3.x int and short are both 16 bits, and long is 32 bits.
		Laterly, int windows and apple short is 16 bits, but int and long are both 32 bits.
		Generally,we use 64 bit CPU nowadays so it is used for 64 bits integer to use long long.

		Generally long long is 64 bits. long is 32 bits. short is 16 bits. int is 16 or 32 bits(be same as the machine word length).
2. 对于long占用的空间比int大的系统,使用long会降低运算速度,如非必要,不用long类型。
3. 对于long占用的空间于int相同的系统,如果确实需要32位的整数时,应使用long类型而不是int类型,以便把程序移植到16位机后仍然可以正常使用,
	因为16位机和32位机的int 位数不同,但是16位机和32位机的long位数相同,long具有一定兼容性。
4. 如果确实需要64位的整数时,才使用long long类型,但是需要注意其在不同机器上的兼容性。
5. 如果确实整数只需要16位,应使用short类型,因为16,32,64位机上short都是16位的,具有兼容性。
*/
/*
16位short          short  [-3|2768,3|2767]                                      unsigned short [0,6|5535]							几万      
32位int            int    [-21|4748|3648,21|4748|3647]                          unsigned int   [0,42|9496|7295]						几十亿
64位long long      long long [-922|3372|0368|5477|5808,922|3372|0368|5477|5807] unsigned long long [0,1844|6744|0737|0955|1615]		几万亿亿
*/

/*
C语言未规定类型的整形值
通常程序代码中使用的整数都被存储位int类型,如果该整数超过了C编译器规定的int的存储范围,编译器会将其视为long int,更大则为unsigned long,
再来就是long long或unsigned long long(当然前提时编译器能识别这些类型)。
对于未用定义语句定义类型的整形型变量:
	IBM PC上的内存地址和C标准函数一般都用long类型;
	为了方便识别整形常量的类型,通常在long类型后加字母‘l’或‘L’(‘L’更优先)。
		在int为16位、long位32位的系统中,会把7作为16位储存,把7L作为32位存储(可以用sizeof(x)来测试)。
		l或L后缀也可用于八进制和十六进制,如020L,0x10L。
	可以使用ll或LL来表示long long类型的值。
		如3LL。
	可以使用u或U 后缀表示 unsigned long long,如5ull,5Ull,5LLU。
*/

#include<stdio.h>

/*可以把整数看作汽车的里程表。当它达到能表示的最大值时会重新从起点开始,有符号整数会从最小负数开始,有符号整数会从0重新开始*/
void integerOverflow(char);//测试整数溢出的情况,输入y则运行,输入其他字符则不运行

/*不定义整数,如int x=111;而是用直接打印出来,看加后缀与不加后缀的结果*/
void printIntegerDirect(char);// 输入y则运行,输入其他字符则不运行

/*打印目前为止学过的所有整数类型*/
void printIntegerTypes(char);// 输入y则运行,输入其他字符则不运行



int main(void){
	system("mode con cp select=65001");
	integerOverflow('y');/*整数溢出*/
	printIntegerDirect('y');// 直接打印
	printIntegerTypes('y');// 打印所有整数类型
	getchar();
	getchar();
}

void integerOverflow(char x){
	if (x=='y')
	{
		int i = 2147483647;
		unsigned int j = 4294967295;
		printf("溢出的算法:设原值为x,周期为T,最终结果为y,则y=f(x+T)=f(x),f(0)=0\n\
			有符号f(-1)=-1(-T/2<y<=T/2-1);\n\
			无符号f(-1)=T-1(0<=y<=T-1).\n");
		printf("%d   %d   %d\n", i,i+1,i+2);/*2147483647   -2147483648   -2147483647*/
		// 无符号整数用u输出
		printf("%u   %u   %u\n", j,j+1,j+2);/*4294967295   0   1*/
		printf("\n");
		printf("突然意识到一个突然意识到一个问题,如果一个式子虽然结果在该范围内,但在运算的过程中,溢出了该整数类型的范围其类型最终会是什么?\n\
			同时引出第二个问题,如果运算的结果溢出了,结果会是什么,以及应该用什么格式化?");
		printf("纯数运算:short*short,如果结果溢出了short的范围,用short进行格式化输出,设原值为x,周期为T,最终结果为y,则y=f(x+T)=f(x),f(0)=0\n\
			有符号结果则会是从(short最小值)-32768开始向更大值变化直到32767(short最大值),f(-1)=-1(-T/2<y<=T/2-1)\n\
			无符号结果则会是从0到65535变化,f(-1)=T-1(0<=y<=T-1)\n\
			这一部分效果等同于前面的integerOverflow()函数的说法,至于unsigned就不进行检验了\n");
		/*利用平方差公式可测*/
		printf("有符号溢出周期长度1倍多32767*2\t=\t2^16-2\t=>\t%hd\n",32767*2);// -2		0~32767 -32768~-2(下一个0就是2^16次方的值)
		printf("无符号溢出周期长度1倍多32767*2\t=\t2^16-2\t=>\t%hu\n",32767*2);// 65534	0~65534
		printf("有符号刚好溢出周期长度2倍131072\t=\t2^17\t=>\t%hd\n",131072);//0 			0~32767 -32768~32767 -32678~0
		printf("无符号刚好溢出周期长度2倍131072\t=\t2^17\t=>\t%hu\n",131072);//0
		printf("有符号溢出周期长度3倍多32767*4\t=\t2^17-4\t=>\t%hd\n",32767*4);// -4
		printf("无符号溢出周期长度3倍多32767*4\t=\t2^17-4\t=>\t%hu\n",32767*4);// 65532
		printf("有符号溢出周期长度29倍多32765*32771\t=\t2^30-9\t=>\t%hd\n",32765*32771);// -9
		printf("无符号溢出周期长度29倍多32765*32771\t=\t2^30-9\t=>\t%hu\n",32765*32771);// 65527
		printf("\n");
		printf("short虽然在纯数字“运算过程中”超过了short int的范围,但是范围不超过int,用short进行格式化,“运算的结果”还是正确的\n\
			因为一开始默认就是用int来进行运算,之后才进行格式化\n");
		printf("32767*32767/32767\t=\t%hd\n",32767*32767/32767);//正确
		printf("但是如果是变量一个个运算还可行吗?\n");
		/*short sb1 = 32767;
		short sb2 =sb1*sb1;
		short sb3 =sb2/sb1;
		short sb4 =sb1*sb1/sb1;
		printf("%hd,%hd,%hd\n",sb2,sb3,sb4);// 1,0,32767
		// 如果是一次性运算可行,分开则不行因为sb2=1 sb3=0.
		*/
		printf("如果是一次性运算可行,分开则不行\n");
		printf("\n");
		/*根据验证,即使用更大的整数类型进行,如int或long格式化进行讨论,其溢出只会按照integerOverflow()中的溢出方式进行溢出,所以之后就不再进行讨论了。*/

		printf("现在验证如果格式化的内容(如131072(2^17)*131072=2^34)超过了格式化本身的范围(如%%d,-2^31~2^31-1),则会抛出警告:\n\
			warning: integer overflow in expression of type 'int' results in '0' [-Woverflow]\n\
			其余情形都一直,如:2^33*2^33的结果用%%ll(-2^63~2^63-1)来进行格式化,会抛出相同的警告。如:\n");
		/*同样用平方差公式来验证*/
		printf("有符号格式化131071*131073\t=\t2^34-1\t=\t%d\n",131071*131073);//-1
		printf("无符号格式化131071*131073\t=\t2^34-1\t=\t%u\n",131071*131073);//4294967295
		printf("有符号格式化8589934591*8589934593\t=\t2^66-1\t=\t%lld\n",8589934591*8589934593);//-1
		printf("无符号格式化8589934590*8589934594\t=\t2^66-4\t=\t%llu\n",8589934590*8589934594);//18446744073709551612
		printf("\n");

		printf("现在验证如果运算的过程中超过了系统最大范围,格式化的结果会是什么(上一验证过程中的第二溢出过程,如果运算结果超过系统的最大范围已经说明还是会循环溢出)?\n");
		printf("结论一printf()的第一个参数的字符串长度有长度限制,会抛出警告:warning: too many arguments for format [-Wformat-extra-args]\n\
			结论二格式化对于过于巨大的整数只要结果超过了long long,进入到需要unsigned long long的范围,只要用到了这个值,都会发出警告:warning: integer constant is so large that it is unsigned\n\
			结论三如果格式化的内容在运算过程中只要用到了unsigned long long型“常数值”就会给出如果一个任意值,所以unsigned long long一般作为恒定值,且不参与任意计算\n\
			特别的是如果是两个非unsigned long long类型的“常数值”计算得出则会出现一个正确的结果,即使结果是unsigned long long,参看上一验证最后一个例子,以及最后两个例子\n\
			结论四计算的过程中用到unsigned long long型或超过的值,只要将其【计算结果用一个变量存储】,则结果会是按照正常的溢出算法显示结果\n");
		printf("有符号格式化9223372036854775806*9223372036854775810\t=\t2^128-4\t=\t%lld\n", 9223372036854775806*9223372036854775810);// 同上的任意值
		printf("无符号格式化9223372036854775807*9223372036854775809\t=\t2^128-1\t=\t%llu\n", 9223372036854775807*9223372036854775809);// 同上的任意值
		printf("无符号格式化9223372036854775807*9223372036854775809\t=\t2^128-1\t=\t%llu\n", 9223372036854775807*9223372036854775809); // 同上的任意值
		printf("9223372036854775809\t=\t2^63+1\t=\t%llu\n",9223372036854775809);// 同上的任意值
		printf("9223372036854775807+9223372036854775808\t=\t2^63-1+2^63\t=\t%llu\n",9223372036854775807+9223372036854775808);// 同上的任意值
		printf("9223372036854775807*9223372036854775807\t=\t(2^63-1)*(2^63-1)\t=\t%llu\n",9223372036854775807*9223372036854775807);// 1
		printf("9223372036854775807+9223372036854775807\t=\t2^63-1+2^63-1\t=\t%llu\n",9223372036854775807+9223372036854775807);// 18446744073709551614
		unsigned long long ullb1= 18446744073709551615*18446744073709551615;
		printf("18446744073709551615*18446744073709551615\t=\t(2^64-1)*(2*64-1)\t=\t%llu\n",ullb1);// 1
		unsigned long long ullb2 = 18446744073709551615*18446744073709551617;
		printf("18446744073709551615*18446744073709551617\t=\t(2^64-1)*(2*64+1)\t=\t%llu\n",ullb2);// 18446744073709551615
		printf("18446744073709551615*18446744073709551615\t=\t%llu\n",18446744073709551615*18446744073709551615);// 同前任意值
		printf("\n");
	}
}

void printIntegerDirect(char x){
	if(x=='y'){
		printf("2147483647:\t\t%d\n",2147483647);
		
		// printf("2147483648:\t%d\n",2147483648);
		printf("对于一个超过32位的int类型的纯整型值,32位系统会自动将其看作long long,同时如果%%d对应long long int类型 会报错。\n");
		printf("warning: format '%%d' expects argument of type 'int', but argument 2 has type 'long long int'.\n");
		
		printf("对于32位系统,int 和 long都是32位,如果想正确打印超过32位的纯整数,只能在后面加ll或LL(一个L结果是溢出错误)。\n");
		printf("同时还必须要修改打印格式,如果还是%%d,还是存在上面的错误。\n");
		printf("\t如果想要打印ll型值,格式只能是%%lld,注意在格式化中只能是小写,不能是%%LL。\n");
		printf("2147483648LL:\t\t%lld\n\n",2147483648LL);
		printf("\n");

		printf("直接打印无符号类型\n");
		printf("%%u格式化unsigned int\n");
		printf("2147483648u:\t\t%u\n",2147483648u);
		printf("%%llu格式化unsigned long long int,而%%ull的ll会被识别为纯字符没有任何作用,这是因为C规定格式化中u只能作为的后缀\n");
		printf("4294967296ull:\t\t%llu\n",4294967296ull);
		printf("4294967296llu:\t\t%llu\n",4294967296llu);
		printf("4294967296ULL:\t\t%llu\n",4294967296ULL);
		printf("4294967296LLU:\t\t%llu\n",4294967296LLU);
		printf("\n");
	}
}

void printIntegerTypes(char x){
	if(x=='y'){
		printf("%%u用于表示unsigned int类型,u作为格式化后缀,且一个格式化中d和u是不能同时出现的\n");
		printf("short可以用h作为前缀,short int可以用%%hd打印\n");
		printf("unsigned short可以用hu作为前缀,unsigned short可以用%%hu打印\n");
		short sa = 32767;
		unsigned short usa = 32768*2-1;
		/*打印short类型*/
		printf("short ranges from %hd to %hd\n",-(sa+1),sa);
		printf("unsigned short ranges from to %hu to %hu\n",usa-usa,usa);
		printf("\n");

		printf("long可以用h作为格式化前缀,即%%ld,unsigned long用%%lu打印\n");// 
		long la = 2147483647;
		unsigned long ula = 4294967295;
		printf("long ranges from %ld to %ld\n",-(la+1),la);
		printf("unsigned long ranges from %lu to %lu\n",ula-ula,ula);
		printf("\n");
		
		printf("long long可以用ll作为格式化前缀,即%%lld\n");
		long long lla = 9223372036854775807;
		unsigned long long ulla = 18446744073709551615;
		printf("long long ranges from %lld to %lld\n",-(lla+1),lla);
		printf("unsigned long long ranges from %llu to %llu\n",ulla-ulla,ulla);
		printf("\n");

		printf("八进制格式化可以用o作为格式化后缀\n");
		printf("64\t=\t8^2\t=\t%o\n",64);
		printf("结论一:八进制与十六进制和10进制格式化溢出处理有区别:\n" );
		printf("\t十进制格式化有溢出警告:\n\
			warning: integer overflow in expression of type 'int' results in '0' [-Woverflow],同时进行溢出处理;\n\
			结果会取溢出值\n");
		printf("\t八进制和十六进制有期盼值警告:\n\
			warning: format '%o' expects argument of type 'unsigned int', but argument 2 has type 'long long int' [-Wformat=]\n\
			结果不会改变\n");
		printf("结论二:八进制o,十进制d,十六进制,无符号十进制u都可作为后缀,但不可以同时出现\n");
		printf("结论三:八进制,十六进制是取原值的绝对值的,无视正负\n");
		printf("结论四:八进制和十六进制是将无符号整数unsigned int作为周期是0-2^32-1\n");
		printf("结论五:八进制,十六进制的溢出算法是:设x为原值,T为周期,y为最终值\n\
			y=f(x+T)=f(x)(0<=y<=2^32-1)\n");
		printf("********示例如下:********\n");
		printf("2^31\t=\t2*(8^10)\t=\t%o\n",2147483648);// 20000000000
		printf("2^31+1\t=\t2*(8^10)+1\t=\t%o\n",2147483649);// 20000000001
		printf("2^32-1\t=\t4*(8^10)-1\t=\t%o\n",4294967295);// 37777777777
		printf("2^32\t=\t4*(8^10)\t=\t%o\n",4294967296);// 0
		printf("2^32+1\t=\t4*(8^10)+1\t=\t%o\n",4294967297);// 1
		
		printf("十六进制格式化可以用x作为格式化后缀\n");
		printf("256\t=\t16^2\t=\t%x\n",256); // 100
		printf("2^31\t=\t8*(16^7)\t=\t%x\n",2147483648);// 80000000
		printf("-2^31\t=\t-8*(16^7)\t=\t%x\n",-2147483647);// 80000000
		printf("2^31+1\t=\t8*(16^7)+1\t=\t%x\n",2147483649);// 80000001
		printf("2^32-1\t=\t16^8-1\t=\t%x\n",4294967295);// ffffffff
		printf("2^32\t=\t16^8\t=\t%x\n",4294967296);// 0
		printf("2^32+1\t=\t16^8+1\t=\t%x\n",4294967297);// 1

		printf("结论六:八进制和十六进制加了ll作为前缀纯数字周期是0~2^63-1\n");
		printf("2^63-1\t=\t8^21-1\t=\t%llo\n",9223372036854775807);// 7|7777|7777|7777|7777
		printf("2^63\t=\t8^21\t=\t%llo\n",9223372036854775808);// 30376700
		printf("2^63+1\t=\t8^21+1\t=\t%llo\n",9223372036854775809);// 30376700(一个任意值)
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llo\n",18446744073709551615);// 30376700(一个任意值)
		printf("2^64\t=\t2*(8^21)\t=\t%llo\n",18446744073709551616);// 0
		printf("2^64+1\t=\t2*(8^21)+1\t=\t%llo\n",18446744073709551617);// 1
		printf("2^63\t=\t8^21\t=\t%llx\n",9223372036854775808);// 61fd60(一个任意值)
		printf("2^63+1\t=\t8^21+1\t=\t%llx\n",9223372036854775809);// 61fd60(一个任意值)
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llx\n",18446744073709551615);// 61fd60(一个任意值)
		printf("2^64\t=\t2*(8^21)\t=\t%llx\n",18446744073709551616);// 0
		printf("2^64+1\t=\t2*(8^21)+1\t=\t%llx\n",18446744073709551617);// 1
		
		printf("结论七:八进制和十六进制加了ll作为前缀变量周期是0~2^64-1\n");
		unsigned long long ullc1 = 9223372036854775808;
		unsigned long long ullc2 = 9223372036854775809;
		unsigned long long ullc3 = 18446744073709551615;
		unsigned long long ullc4 = 18446744073709551616;
		unsigned long long ullc5 = 18446744073709551617;
		printf("2^63\t=\t8^21\t=\t%llo\n",ullc1);// 1000000000000000000000
		printf("2^63+1\t=\t8^21+1\t=\t%llo\n",ullc2);// 1000000000000000000001
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llo\n",ullc3);// 17|7777|7777|7777|7777|7777
		printf("2^64\t=\t2*(8^21)\t=\t%llo\n",ullc4);// 0
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llo\n",ullc5);// 1
		printf("2^63\t=\t8^21\t=\t%llx\n",ullc1);// 8000000000000000
		printf("2^63+1\t=\t8^21+1\t=\t%llx\n",ullc2);// 8000000000000001
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llx\n",ullc3);// ffffffffffffffff
		printf("2^64\t=\t2*(8^21)\t=\t%llx\n",ullc4);// 0
		printf("2^64-1\t=\t2*(8^21)-1\t=\t%llx\n",ullc5);// 1

		printf("\n");
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从零开始的智障生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值