各式各样的操作符详解 现在打下的所有基础,都在为你未来的能力上限做准备 1.算术操作符 2.原码,反码,补码 3.移位操作符(移(2进制)位操作符) 4.位操作符 (针对整数且为2进制
各式各样的操作符详解
现在打下的所有基础,都在为你未来的能力上限做准备
1.算术操作符
2.原码,反码,补码
3.移位操作符(移(2进制)位操作符)
4.位操作符 (针对整数且为2进制位,均为补码计算)
5.赋值操作符
6.单目操作符
7.关系操作符
8.逻辑操作符
9.条件操作符
10.逗号表达式
11.下标引用,一个数组名,一个索引值
12.表达式求值---重点
1.算术操作符
对于除法操作符,两边的操作数都是整数,执行的是整数除,若想得到小数,除号两端至少有一个为浮点数/取模(取余),计算的是整除之后的余数
取模操作符(%),计算的是整除之后的余数,只能用整型类型的操作
2.原码,反码,补码
例如: a = 1000000000000000000000000000001010-原码
00000000000000000000000000001010-反码
00000000000000000000000000001010-补码正数的原码反码补码相同如b= -10 ,下面写出b的原码,反码,补码10000000000000000000000000001010-原码--按照一个数的正负,直接写出它的二进制表示形式
11111111111111111111111111110101-反码--原码的符号位不变,其它位取反(第一位是符号位)
11111111111111111111111111110110-补码-反码加1补码变原码:先符号位不变,其它位按位取反,再+1下图可以清晰总结原反补:
3.移位操作符(移(2进制)位操作符)
左移操作符:左边丢掉,右边补0计算机在存储中存储的永远都是补码,所以在移位时,移动的是补码。符号位(0是正数,1是负数)
整型占4个字节(32bit)
内存中存储的其实是:补码的二进制
所以在参与移位时,移动的都是补码--所以移位操作符的用法可以理解了例如:a =10;
a << 1;//2进制移位
先写出10的补码:
00000000000000000000000000001010
00000000000000000000000000010100 (左移一位后的结果)但是这个过程a不变,变的是a向左移动的表达式这个结果变,a本身不变
比如: a=10;b=a+2;b=12,但是a本身不变,还是10
若想让a变化,可以写成 a>>=1;(a = a>>1)又比如:int a = -10;
int b = a << 1;先写出a的原反补:10000000000000000000000000001010--原码
11111111111111111111111111110101--反码
11111111111111111111111111110110--补码左移操作符:(补码)左边丢掉,右边补0
11111111111111111111111111101100--补码左移后的结果,是b的补码
10000000000000000000000000010011--计算过程
10000000000000000000000000010100--b的原码
由于打印(肉眼可见的)出来的都是原码,但是计算机存储的是补码,所以计算机要转换成原码再打印出来
总结,左移1位有×2的效果
右移操作符(看完左移操作符,就懂右移操作符了)
1)算术右移(平常见到)--也是计算机计算的方法
算数右移-右边丢弃,左边补原来的符号位如 a =-1
100000000000000000000000000000001--a的原码
111111111111111111111111111111110--a的反码
111111111111111111111111111111111--a的补码b= a>>1
11111111111111111111111111111111--a右移的结果,也就是b,但是a本身不变2)逻辑右移(不怎么用)
逻辑右移-右边丢弃,左边直接补0
4.位操作符 (针对整数且为2进制位,均为补码计算)
& | ^
按位与,按位或,按位异或
& -- 对应的2进制位有0则为0,两个同时为1,才为1按位或
对应的二进制位,有1则为1,两个同时为0才为0按(二进制)位异或
对应的2进制位,相同为0,相异为1下面有一道面试题:面试题:不能创建临时变量(第三个变量),实现两个正数的交换使用异或操作符求解先清楚两条计算规则:
1)a^a = 0
2)0^a = aa = a^b; //此时a相当于 a^b
b = a^b; //等价于 a^b^b == a^0 ==a ,所以b =a
a = a^b; //等价于a^b^a == a^a^b == 0^b ==b
即a=b
即可完成两个正数的交换结论 :异或支持交换律异或虽好,不要贪杯
1.可读性差
2.效率不如使用临时变量的方法
3.只能针对整数的交换
5.赋值操作符
赋值操作符是一个很棒的操作符,它可以让你得到一个你之前不满意的值,
也就是你可以重新赋值好处:可以连续赋值a= x = y+1 ; 也是从右到左开始赋值
但这种方法不易于理解,不易于调试
等同于:
x = y+1;
a = x;
6.单目操作符
1.+= 2. -=3. *= 4. /= 5. %= 6. >>= 7. <<=
易于理解
7.关系操作符
操作符有两个操作数,叫双目操作符,比如 1+3,+号为双目操作符,同理,只有一个操作数,叫单目操作符!:逻辑反操作
-:负值
+:正值
&:取地址
&地址
> >= < <= != ==一个等号叫赋值,两个等号叫判断
判断闰年的规则就很好地说明这两个操作符 1,能被4整除,并且不能被100整除
2.能被400整除int main()
{
int y = 2048;
if ((y % 4 == 0 && y % 100 != 0) || (y %400 == 0))
{
printf("yes\n");
}
}sizeof:操作数的类型长度(以字节为单位)
sizeof - 是关键字,也是操作符
功能是计算大小~:对一个数的二进制按位取反(包括符号位)
~ 按位取反(二进制数)(只能针对整数)
a = 0;
11111111111111111111111111111111 -- ~a的补码
打印出来要变成原码,但是在计算机存储中仍然是补码
10000000000000000000000000000001 --~a的原码
打印出来就是 -1--:前置,后置--
++:前置,后置++
*:间接访问操作符(解引用操作符)
(类型):强制类型转化例如int main()
{
int a = (int)3.14;
//强制将double类型转换成int类型,相当于只是拿了整数部分 printf("%d\n", a);
return 0;
}又如:int main()
{
srand((unsigned int)time(NULL));
//(unsigned int)--强制类型转换成无符号类型
//NULL空指针
} 强制类型转换是在万不得已的情况下才用的(强扭的瓜不甜)布尔类型:补充:
布尔类型:
C99及以后引入的
布尔类型就是用来表示真假的类型 -- _Bool
只有true 和false 的赋值总体来说,逻辑操作符如下:
9.条件操作符
exp1 ? exp2 : exp3 -- 三目操作符
表达式1如果为真,表达式2计算,表达式2计算的就是整个表达式的结果
表达式1如果为假,表达式3计算,表达式3计算的就是整个表达式的结果
求两个数的较大值int main()
{
int a = 10;
int b = 20;
int c = a > b ? a:b;//(exp1 ? exp2 : exp3)
printf("%d\n", c);
三目操作符用于实现逻辑比较简单的操作
return 0;
}
10.逗号表达式
10.逗号表达式
exp1 ,exp2,exp3,exp4,......expN
从左向右依次计算,整个表达式的结果是最后一个表达式的结果int main()
{
int a = 1;
int b = 2;
int c = (a > b, a = b + 10, a, b = a + 1);
最后决定c的是最后一个式子,从左到右表达式一次执行,执行的结果
如果改变最后一个表达式,那么也会影响c的值
printf("%d\n", c);
}
11.下标引用--一个数组名,一个索引值
一段代码搞定:理解透彻int main()
{
int arr[10] = { 1,2,3,4,5 };
printf("%d\n", arr[4]); //[] -- 下标引用操作符,操作数是 arr,4
两者缺一不可
return 0;
12.表达式求值---重点
表达式求值的顺序一部分是由操作符的优先级和结合性决定的
同样,有些表达式的操作数在求值的过程中可能要转换为其他类型12.1隐式类型转换整型提升--针对类型小于整型的:char short
char short int long...
1 2 4 8
整型提升是按照变量的数据类型的符号位来提升!!!
由于char类型是一个字节,int类型是4个字节,所以用char类型无法完整表示int类型
故会自动发生截断,只读取最后一个字节的二进制为,即8个二进制位
现在讨论char类型的取值范围
最高位是符号位,符号位为0,表示整数,最大为011111111--127
符号位为1,表示负数,最小为
char类型中 0,1,2...127,-128,-127,-126,...0,1,2,...127,-128...是一个圆环
char类型中,127+1==-128 , -128+1=-127, -127+1= -126
所以打印出来是-126//short -32768~32767
char--有符号的char的取值范围是 -128~127
无符号位的char的取值范围是0~255(因为第一位不再是符号位)
char -1字节-8比特位 有2^8次方种可能性//以下例子说明整型提升的存在
int main()
{
char c = 1;
printf("%u\n",sizeof(c));//1-char类型是1个字节
//由于+c是一个表达式,-c也是一个表达式子,所以会发生整型提升,提升后变成4个字节
printf("%u\n", sizeof(+c));//4-整型提升后,整型类型是4个字节
printf("%u\n", sizeof(-c));//4-整型提升后,整型类型是4个字节
// %u打印无符号十进制
}
//通俗的讲,整型提升是对字节不足的,进行字节补充,截断是字节超出范围的,把超出的高位截断
//12.2算数转换--大于int的都属于算数转换(隐式转换,也就是偷偷发生)
//如果某个操作符的各个操作数属于不同类型,
//那么除非其中一个操作数的转换为另一个操作数的类型,
//否则操作就无法进行。//long double
//double
//float
//unsigned long int
//long int
//unsigned int
//int
//以上转换级别都是从下往上递增,即如果发生算数转换,一定是从下往上转换
////12.3操作符的属性
//1.操作符的优先级
//2.操作符的结合性
//3.是否控制求值顺序
//首先确定优先级,相邻操作按优先级高低计算
//优先级相同的情况下,考虑结合性//1.优先级:相邻操作符才讨论优先级
//int main()
//{
// int a = 1;
// int b = 2;
// int c = 4;
// int d = a * 4 + b / 3 + c;
//
// //相邻才讨论优先级,无法确定 * 和 / 谁先算
// //相邻操作符优先级相同的情况下,考虑2.结合性
// return 0;
//}补充:
算术转换:
long double
double
float
unsigned long int
long int
unsigned int
int
当连个不同类型的值比较或相加减时,默认从低到高转换,即向上转换关注我,给你更多你意想不到的惊喜