C语言【进制、原反补码、数据类型】
1、二进制、八进制、十进制、十六进制在C语言中的使用(赋值及输出)?
/**
二进制
赋值时以 0b 或 0B 开头;
输出时没有所属占位符, 十六进制整数输出也比较直观
*/
int num_bin = 0b110;
printf("%d\n", num_bin); // 以十进制整数形式输出
//其他进制输出形式略,总之就是没有二进制形式的输出
/**
八进制
赋值时以0(零)开头;
占位符:%o (小写字母o , 八进制整数)
*/
int num_oct = 0123;
printf("%o\n", num_oct); // 以八进制整数形式输出
/**
十进制
赋值时正常表示
占位符:%d 表示输出形式为十进制整数
*/
int num_deci = 123456;
printf("%d\n", num_deci);
/**
十六进制
以0x或0X开头
占位符: %x 输出十六进制整数(A-F输出为小写)
%X 输出十六进制整数(A-F输出为大写)
%#x 输出0x样式十六进制整数
%#X 输出0X样式十六进制整数
*/
int num_hex = 0xff;
printf("%x\n", num_hex);
printf("%#x\n", num_hex);
printf("%#X\n", num_hex);
拓展问题:有没有浮点类型二/八/十六进制的数的展示 ?输出呢?
似乎有,似乎用处不大。来一段:
float hex_float = 0x1P3;
printf("hex_float = %f\n", hex_float); // 输出为 hex_float = 8.000000
在这里,0x1P3
是一种用科学计数法表示十六进制浮点数的方式。在这个例子中,1P3
表示1乘以2的3次方,也就是8。
2、进制转换略。 遗留问题: 浮点数的进制转换?
3、机器数指一个数在计算机中存储的二进制原样;真值指按规则编码后表示的值,比如1001这个二进制数,如果把最高位的1表示为符号位,则其真值为-1。
4、原反补码是什么及各自的转换。
原码:最高位表示符号位(0正、1负)的机器数。
反码:正数反码即原码;负数反码符号位不变,其他位取反。
反码存在的意义就是为了求补码。
补码:正数的补码即原码;负数的补码即反码+1。
补码存在的意义就是为使计算机运算更方便,因为计算机没有设计减法器,听说减法器不如用补码更简洁和高效。
补码的设计原理是:让负数原码的绝对值和负数的补码相加为全零(最高位溢出),这个补全后的数即为该存储大小能表示的个数,2字节的话这个数即为65536,这样的话有效位数就全为0了。
比如:2+(-2)=0。 -2的补码离有效位全0少2;+2离有效位全0多了2,对于有效位全0来说刚好互补。
这样设计的好处为:作减法运算时,可视为正数和负数相加。
运算时,符号位也参与运算。
负数补码转原码时,也可以直接取反后+1得到。
/** 下面的代码中 short 占两个字节,能表示65536个数,最高位溢出,有效位全0 -2的在内存中以补码形式存储,表示为十进制即为65534,要用%u输出 也可以想-2离有效位全0即65536少2,即65534 */ unsigned short num_byte2 = -2; printf("%hu\n", num_byte2); // 输出为 65534 hu表示无符号短整型 short num_byte2_1 = -2; printf("%hu\n", num_byte2_1); // 输出为 65534
问题:参考上面的代码,下面的代码为什么会这样子输出?
unsigned short num_byte2 = -2; // 这一步将num_byte2转换为65534 printf("%u\n", num_byte2); // 输出为 65534 short num_byte2_1 = -2; // 在这一步num_byte2_1还是-2 printf("%u\n", num_byte2_1); // 输出为 4294967294 转换为无符号时short占不下了,按四个字节来,就变成了 4294967296-2, 即 4294967294
5、基本数据类型
整型
短整型 short ---------- 2Byte
有符号短整型 signed short / short 占位符为: %hi表示范围:-32768到32767 字面量无尾缀
无符号短整型 unsigned short占位符为: %hu表示范围:0到65535 字面量无尾缀表示
整型 int ---------- 16位机 2Byte; 32位机 4Byte
有符号整型 signed int / int 占位符: %d 表示范围: 根据位数决定
一般拼写上一个没超过int范围的数默认字面量的类型为int,除非在字面量后面加尾缀。
无符号整型 unsigned int 占位符 %u 表示范围: 根据位数决定 字面量尾缀为u或U
长整型 long ----------- 32位机 4Byte; 64位机 8Byte 问题: 我64位机咋还是4Byte? windows的问题。Linux就是8个。不同系统使用的数据模型不同,导致long表示的范围不能确定无二。
有符号长整型 signed long / long 占位符:%ld 表示范围:不做掌握 字面量尾缀 l或L
无符号长整型 unsigned long 占位符: %lu 表示范围:不做掌握 字面量尾缀lu或ul
长长整型 long long ------------ 8Byte
有符号长长整型 signed long long / long long 占位符: %lld 表示范围:很大很大 字面量尾缀ll或LL
无符号长长整型 long long 占位符: %llu (l和u位置不可互换) 表示范围:很大很大 字面量尾缀llu或LLU
注意:
任何系统的pointer(指针类型)位数和系统一致,比如64位即8Byte;
char、int、long long不随系统改变;
尽量不使用long;
想确保int为4Byte可以使用stdint.h库里的 int32_t 类型浮点型
单精度浮点型 float --------- 4Byte
表示范围:1.2E-38 到 3.4E+38
字面量尾缀f或F,给不加小数点的字面常量尾缀f或F会报错
占位符:对于printf(...)来说,单精度和双精度都是 %f
双精度浮点型 double --------- 8Byte
表示范围 2.3E-308 到 1.7E+308
加了小数点的字面量默认为double,无需尾缀
占位符:对于printf(...)来说,单精度和双精度都是 %f
长双精度浮点型 long double ------------ 32位机 10Byte; 64位机16Byte
表示范围 很大很大
字面量尾缀l或L,给不加小数点的字面常量尾缀f或F会表示为long
占位符:%Lf
浮点数打印时默认保留六位小数,可自行调整。如下:
double num_doub = 123456789.23956; // 注意: 这个保留的两位是四舍五入而不是截取 (我用的gcc,别的编译器没试过) printf("%20.2lf\n", num_doub); // 总共输出二十个字符,不够前面补空格。小数点后保留两位,如果整数位大于二十,则仍然完整输出整数位,小数位保留两位(注意.2后面是字母l,不是数字1) // %e 占位符可以输出浮点数的科学计数法表示形式(适用float和double) 长双用%Le(L大写) double num_double2 = 123.4; printf("%e\n", num_double2);
字符型 char ------- 1Byte
占位符: %c
不能存中文字符,想存中文字符用指针或数组。
本质就是一个整数。不同设备把char默认为有符号/无符号的类型。一般是有符号,即 -128 到 127
布尔型 _Bool
6、数据类型转换
隐式转换(自动类型转换)
short(2)/ char(1) ----> int(2/4) -----> unsigned int (2/4) --------> long(4/8) ------> unsigned long(4/8) ----> long long(8) ------> float(4) ------> double(8) ------> long double(10/32)
浮点转整型有可能出现溢出(如果整数很大)或者 精度缺失
显示转换(强制类型转换,略) 整数小转大具体细节按补码计算。涉及浮点数的小转大不会。
float num_f = 12.3f; double num_dou = (double) num_f; printf("%lf\n", num_dou); // 输出 12.300000
7、sizeof(...)的使用,格式占位符,返回的类型等。
sizeof(类型/变量名/字面量/表达式)
如果不是查看 类型或表达式 的大小,可以使用 sizeof 变量名/字面量
占位符为 %zu 或 %d
返回类型为size_t,根据系统决定实际类型。
返回类型的字节个数,如果查看某个字面量的字节占用个数,查的是它默认的使用类型字节数。
8、补充
1. 转义字符
\b 退格; \n 换行符; \r 回车符; \t 制表符; \加单双引号或斜杠在特殊情况下转义为它们本身等
2. C语言中非0即为真,-1也是真。
3. <stdint.h> 和 <stdbool.h> 提供的类型,略。
#include<stdio.h>
#include<stdint.h>
// 精确宽度整数类型
// 64位,很多计算机底层为long long , %d 输出会数值错乱
int64_t e1 = 4500000000;