算数操作符
1.除了%操作符之外,其他的几个操作符可以作用于整数和浮点数。 2.对于/操作符,如果两个操作数都为整数,执行整数除法,而只要有浮点数执行的就是浮点数除法 3.%操作符的两个操作数必须为整数,返回的是整除之后的余数
移位操作符(只能作用于整数)
右移动(>>)
1.算术右移(常见)
右边丢弃,左边补原符号位
2.逻辑右移
右边直接丢弃,左边补0
警告:对于移位操作符,不要移动负数位,这是一种未定义操作符
//int main() {
// int a = 16;
// //>> -- 右移操作符
// //移动的是二进制位
// // 00000000000000000000000000000000
// //16 -- 10000
// // 00000000000000000000000000010000 -- 16
// // 00000000000000000000000000001000 -- 8
//
// int b = a >> 1;
// printf("%d\n", b);//8
// return 0;
//
//}
//int main() {
// //二进制中首位的1表示负号
// int a = -1;
// //整数的二进制表示有:原码,反码,补码
// //储存到内存的是补码
// //10000000000000000000000000000001 - 原码(-1)
// //11111111111111111111111111111110 - 反码
// //11111111111111111111111111111111 - 补码
// return 0;
//}
左移操作符
左边丢弃,右边补齐
int main() {
int a = 5;//00000000000000000000000000000101 -- 5
//左移操作符
int b = a << 1;//00000000000000000000000000001010 -- 10
return 0;
}
位操作符(操作数必须是整数)
& -- 按位与
| -- 按位或
^ -- 按位异或
int main() {
//& - 按2进制位与
//int a = 3;
//int b = 5;
//int c = a & b;//1
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000001 -- 按位与
//printf("%d\n", c); 1
// | -- 按二进制位或
//int a = 3;
//int b = 5;
//int c = a | b;
////00000000000000000000000000000011
////00000000000000000000000000000101
////00000000000000000000000000000111
//printf("%d\n", c);//7
// ^ -- 按二进制位异或
//相同为0,相异为1
int a = 3;
int b = 5;
int c = a ^ b;
//00000000000000000000000000000011
//00000000000000000000000000000101
//00000000000000000000000000000110
printf("%d\n", c);//6
return 0;
}
两个变量交换
int main() {
int a = 3;
int b = 6;
//int tmp = 0;//创建临时变量的方法
printf("before: a=%d b=%d\n", a, b);
//tmp = a;
//a = b;
//b = tmp;
//加减法交换 - 可能会溢出
//a = a + b;//a = 8 b = 6
//b = a - b;//a = 8 b = 3
//a = a - b;//a = 6 b = 3
//异或的方法
//a - 011 b - 110
a = a ^ b;//a -- 101
b = a ^ b;//b -- 011 = 3
a = a ^ b;//a -- 110 = 6
printf("after:a=%d b=%d\n", a, b);
return 0;
}
求二进制里面1的个数
int main() {
int num = 0;
int count = 0;//计数器
scanf("%d", &num);
int i = 0;
for (i = 0; i < 32; i++) {
if (1 == ((num >> i) & 1))
//每循环一次如果符合条件则计数一次
count++;
}
printf("%d\n", count);
}
赋值操作符
变量创建的时候给值叫初始化
变量创建过了之后给值叫赋值
复合赋值
单目操作符
举个别例子
int main() {
int a = 0;
if (!a) { //a为假打印
printf("呵呵!\n");
}
return 0;
}
&(取地址操作符)
*(解引用操作符)
int main() {
int a = 0;
int* p=&a;//取地址操作符
*p;//解引用操作符 -- 通过*p找到a
return 0;
}
sizeof
sizeof()里的表达式不参与运算
int main() {
int a = 10;
char c = 'r';
char* p = &c;
int arr[10] = { 0 };
//sizeof 计算的变量所占内存空间的大小,单位是字节
printf("%d\n", sizeof(a));//4 -- 通过变量名
printf("%d\n", sizeof(int));//4 -- 通过类型访问
printf("%d\n", sizeof(c));//1
printf("%d\n", sizeof(char));//1
printf("%d\n", sizeof(p));//8
printf("%d\n", sizeof(char*));//8
printf("%d\n", sizeof(arr));//40
printf("%d\n", sizeof(int [10]));//40
return 0;
}
~(按位取反)
int main() {
int a = 11;
a = a | (1 << 2);
printf("%d\n", a);//15
//00000000000000000000000000001011
//00000000000000000000000000000100
//1<<2
//00000000000000000000000000000001
//a - 00000000000000000000000000001111
a = a& (~(1 << 2));
printf("%d\n", a);//11
//1<<2 - 00000000000000000000000000000100
//~(1 << 2) - 11111111111111111111111111111011
//a - 00000000000000000000000000001111
//a& (~(1 << 2)) - 00000000000000000000000000001011
//int a = 0;
////~ 按(2进制)位取反
////00000000000000000000000000000000
////11111111111111111111111111111111 - 补码
////11111111111111111111111111111110 - 反码
////10000000000000000000000000000001 - 原码
//printf("%d\n", ~a);
return 0;
}
前置++,后置++
int main() {
int a = 10;
//printf("%d\n", ++a);//前置++,先++后使用 - 11
printf("%d\n", a++);//后置++,先使用后++ - 10
return 0;
}
强制类型转换
int main() {
int a = (int)3.14;
printf("%d\n", a);
return 0;
}
隐式类型转换
整型提升
C的整形运算总是至少以缺省整型类型的精度来进行运算的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为整型提升
整形提升的意义
表达式的整形运算要在CPU的相应运算器件内执行,CPU内整形运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
因此,即使两个char类型的相加,在CPU执行时实际上也先要转换为CPU内整形操作数的标准长度。 通用CPU是难以直接实现两个8比特字节直接相加运算,所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行运算
//int main() {
// char a = 3;
// //00000000000000000000000000000011
// //00000011 - a
// char b = 127;
// //00000000000000000000000001111111
// //01111111 - b
//
// //a和b如何相加
// //00000000000000000000000000000011
// //00000000000000000000000001111111
// //00000000000000000000000010000010
//
// char c = a + b;
// //c=10000010
// //11111111111111111111111110000010 - 补码
// //11111111111111111111111110000001 - 反码
// //10000000000000000000000001111110 - 原码
// //-126
// printf("%d\n", c);// -126
// return 0;
//}
如何进行整型提升
整型提升是按照变量的数据类型的符号位来提升的
//int main() {
// char a = 3;
// //00000000000000000000000000000011
// //00000011 - a
// char b = 127;
// //00000000000000000000000001111111
// //01111111 - b
//
// //a和b如何相加
// //00000000000000000000000000000011
// //00000000000000000000000001111111
// //00000000000000000000000010000010
//
// char c = a + b;
// //c=10000010
// //11111111111111111111111110000010 - 补码
// //11111111111111111111111110000001 - 反码
// //10000000000000000000000001111110 - 原码
// //-126
// printf("%d\n", c);// -126
// return 0;
//}
//例题
int main() {
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
printf("a");
if (b == 0xb600)
printf("b");
if (c == 0xb6000000)
printf("c");
return 0;
}
//例题2
int main() {
char c = 1;
printf("%u\n", sizeof(c));//1
//c只要参与表达式运算,就是发生整型提升,表达式+c,就会发生提升,所以sizeof(+c)是4个字节
//表达式-c也会发生整型提升,sizeof(-c)是4个字节,但是sizeof(c)就是1个字节
printf("%u\n", sizeof(+c));//4
printf("%u\n", sizeof(!c));//1
return 0;
}
算数转换
long double
double
float
unsigned long int
long int
unsigned int
int
算术转换要合理,不然会有一些潜在问题
操作符的属性
复杂表达式的求值有三个影响因素。
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序
两个相邻的操作符先执行哪个?取决于它们的优先级,如果是相同操作符,则看他们的结合性
//int main() {
// int a = 10;
// int b = 20;
// int c = b + a + 3;
// return 0;
//
//}
一些问题表达式
表达式1
a*b+c*d+e*f//问题表达式
计算机的运算顺序
a*b
c*d
a*b+c*d
e*f
a*b+c*d+e*f
或者:
a*b
c*d
e*f
a*b+c*d+e*f
//假如将数换成表达式,可能会出现错误
表达式2
c + --c;
注释:同上,操作符的优先级只能决定自减的运算在+的运算的前面,但是我们并没有办法得知,+操作符的左操作数的获取在右操作数之前还是之后求值,所以结果不可预测的,是有歧义的。
表达式3
int main(){
int i=10;
i = i-- - --i*(i=-3) * i++ + ++i
printf("i=%d\n",i)
return 0;
}
表达式4
int fun() {
static int count = 1;
return ++count;
}
int main() {
int answar;
answar = fun() - fun() * fun();
printf("%d\n", answar);
return 0;
}
表达式5
int main() {
int i = 1;
int a = (++i) + (++i) + (++i);
printf("a= %d\n", a);
return 0;
}
Linux用gcc下结果是10
win用VS下结果是12
所以不要写华而不实的代码,要写有唯一计算路径的代码
表达式3在不同的编译器中测试结果:非法表达式程序的结果
这个操作符优先级图我是在网上找的,也有不同的但是都差不多。