C语言(二) 补码,运算值与表达式
补码
正数的原码反码补码相同
计算机存正数和负数存的都是补码
负数的原码是正数原码符号位变为1
反码是原码按位取反 符号位不改
补码是反码加1
8 00001000
-8 原码 10001000
反码 11110111
补码 11111000
大小端问题 :
高位数据在高字节 低位数据在低字节 arm
高位数据在低字节 低位数据在高字节 x86
类型转换
隐式转换
不同类型之间可以进行混合运算,但是会发生自动类型转换
不同类型数据在一起进行数学运算的时候,先把类型转成一致
C语言自动转 但是要注意 最好自己手动转
提升原则:小的转大的
char ->short -> int -> double
思考:
10 + ’a’ + 1.5 - 8765.1234 * ’b’ 是什么类型?
强制类型转换
强制类型转换
一般形式:(类型名)(表达式)
例 (int)(x + y)
(int)x + y
(double)(3/2)
(int)3.6
说明:强制转换得到所需类型的中间变量,原变量类型、变量值保持不变
较高类型向较低类型转换时可能发生:精度损失问题
类型转换本质
unsigned short a = 256;
char b = a;
printf("%d",b);
这样赋值后,输出变量b的值并非预期的256,而是0,原因是256超出了char类型能够装载最大值,b只截取了a的低8位的数据,如下:
当把占字节较小的数据赋值给占字节较大的数据时,可能出现以下两种情况。
第1种情况,当字节较大数是无符号数时,转换时新扩充的位被填充成0
char b = 10;
unsigned short a = b;
printf("%u",a);
这样赋值后,变量a中输出的值是10,原因如下:
第2种情况,当字节较大数是有符号数时,转换时新扩充的位被填充成符号位
char b = 255;
short a = b;
printf("%d",a);
这样赋值后,变量a输出的值是-1,变量a扩充的高8位,根据变量b的最高位1都被填充成了1,所以数值由正数变成了负数,因为变量a的最高位符号位是1,至于为什么16个1表示的是-1,涉及到二进制数的原码和补码问题,大家回顾下补码。转换图示如下:
运算符与表达式
字符类型的存储:
字符本质是整数
编译器做的事很复杂:
编程语言,编译器,计算机 外国人发明的
他们用到的符号 不多 加起来不超过256个
a-z A-Z @!#$ 0-9
char 1个字节
象形文字 我们的符号多不多
解决方案1: 中文的符号 不再是字符类型 而是字符串
有些编译器 一个汉字 gbk 2个字节 有些 一个汉字 ufg-8 3个字节
解决方案2: 字符集
char 1字节
vs char_t 2字节 unsigned short
小数的存储
float 符号位s(1位)和、指数e(8位)、 底数m(23位) 4
double 符号位s(1 bit)指数e(11 bit)尾数(52 bit) 8
最高位为符号位: 0负 1正
指数:2进制科学计数法
尾数:
10进制科学计数法:
1111.111
1.111111*10^3
1.111111E3
0.0000009 9E-7
2进制科学计数法:
1.5 十进制
1.1 二进制
11.625 十进制
0.625*2=0.5
1011.101 二进制
1.011101E3 —> 1011.101
2^2 2^1 2^0 . 0.5 0.25 0.125
float: 0 00000011 00000000000000000011101
double: 0 00000000011 00…000000000000000011101
11.625
0.6252 == 1.250
0.252 == 0.5
0.5*2 == 1
十进制: 0.625
二进制: 0.101
二进制科学计数法: 1.01E-1
float: 0 11111111 00000000000000000000001
表达式:
具备唯一返回值的式子
返回值:
就是算完后有一个值
运算符
具备特殊功能的符号
, 连接多个语句组成一条语句
= 赋值运算符 赋值
把右边的值 赋予 左边 绑定的内存段
; 结束一条语句
() 提升优先级
左值 右值 左操作数 右操作数
赋值运算符: = += -= *= /= %= &= |= ^= <<= >>= n = 5; n += 5;// n = n + 5; n <<= 5;// n = n << 5; 自运算符: n-- --n n++ ++n n-- 后自减 n++ 后自增 先参与运算,后自增 --n 前自减 ++n 前自增 ++n == n=n+1 == n+=1 先自增 后参与运算 逻辑运算符: ! && || 关系运算符: > < == != >= <= 其他运算符: , ; # & ?: () () () [] [] {} <> '' "" * . -> \ / // /**/
目数:
单目 双目 三目 操作数的个数
, 双目
; 单目
?: 唯一的三目运算符
() 强制类型转换 双
(int)表达式
() 优先级提升
整体是一个表达式 表达式1 ? 表达式2 : 表达式3
整体表达式 的结果 取决于 表达式1的逻辑值
如果为真:整体表达式 的结果 等同于 表达式2
如果为假:整体表达式 的结果 等同于 表达式3
位运算符: ~ & | ^ << >> 针对二进制位 数学运算 字符串匹配 加密解密 音视频 pe ~ 单目 按位取反 负数的二进制形式 正数的 原码 反码 补码 相同 负数的 原码 反码 补码 计算机存储的是补码 计算机存储的都是 二进制形式 原码 一个负号 等同于 求一次补码 补码 : 反码 + 1 反码 : 按位取反 ^ 按位异或: 相同为0 不同为1 & 按位与 双目 两边对应的二进制位 做 按位与运算 都为1才为1 1&0 == 0 0&1 == 0 0&0 == 0 1&1 == 1 1&1 == 1 0&1 == 0 任何数据&1 等于它本身 任何数据&0 等于0 | 按位或 双目 两边对应的二进制位 做 按位或运算 都为0才为0 1|0 == 1 0|1 == 1 0|0 == 0 1|1 == 1 任何数据|1 等于 1 任何数据 | 0 等于它本身 << 按位左移: n<<m n左移m位 左边去掉m个二进制位,右边补m个0 128 00000000 00000000 00000000 10000000 << 24 符号位去掉: 10000000 00000000 00000000 00000000 >> 按位右移: n>>m n右移m位 右边去掉 m 个二进制位,左边补m个符号位
逻辑值:
要么真 1 要么假 0
值 和 逻辑值
非0为真 0为假
1.1 真
‘a’ 真
66.66 56 “abcdefg” 真
‘0’ 48
‘\0’ 0 假
“” 0 假
0 假
NULL
程序的运行顺序
和现代阅读顺序相同
从上往下 从左往右
从上往下一行一行执行
优先级
看主体 看运算符