1.左移操作符
正整数的原码反码补码相同都等于原码, 负整数的原码、反码、补码是要计算的,计算方法如下:
- 原码:把数字直接用二进制表示就是原码
- 反码:原码的符号位不变,其他位按位取反就是反码
- 补码:反码加一就是补码
并且,在内存中存储的是二进制的补码。所以移位操作符是移动的是一个二进制位,且是补码。
具体做法是左边丢弃右边补0。左移有乘2的效果。
2.右移操作符
右移操作符分为两种:
1.算术移位:右边丢弃,左边补原符号位
2.逻辑移位:右边丢弃,左边补0
要判断是算术移位还是逻辑移位用一个负数。
注意:1.左移操作符和右移操作符都只针对整数,浮点数不适用
2.对于移位运算符,不要移动负数位,这个是标准未定义的
3.位操作符
- & —按(2进制)位与
- | — 按(2进制)位或
- ^ —按(2进制)位异或
都是对补码进行位操作
&是只有两位同为1结果才为1,不然结果都为0
| 是只要有1结果就为1,只有两位都为0结果才是0
^ 是相同为0,相异为1
int main()
{
int a = 3;
int b = -5;
int c = a & b;
//000000000000000000000011 - 3的补码
//100000000000000000000101
//111111111111111111111010
//111111111111111111111011 -5的补码
//000000000000000000000011 -按位与的结果(也是补码)
//111111111111111111111011 -按位或的结果(补码)
//111111111111111111111000 -按位异或的结果(补码)
//
return 0;
}
示例:
问题:不创建临时变量交换两个数
(解法一)
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a + b;
b = a - b;
a = a - b;
printf("交换后: a=%d b=%d\n", a, b);
return 0;
}
注意:在a和b都在范围内时,a+b的和也可能会溢出。
(解法二)
int main()
{
int a = 3;
int b = 5;
printf("交换前:a=%d b=%d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
注意:两个相同的整数异或的结果为0,一个整数和0异或的结果为这个数本身。并且异或操作符支持交换律及结合律。所以 3^5^3的结果是5 。
补充:~是按位取反
sizeof
sizeof() 是一个判断数据类型或者表达式长度的运算符
注意:sizeof是一个单目操作符 ,而不是函数。而strlen是库函数,不是操作符。
int main()
{
int a = 0;
printf("%d\n", sizeof(a));//正确
printf("%d\n", sizeof(int));//正确
printf("%d\n", sizeof a);//正确
printf("%d\n", sizeof int );//错误
return 0;
}
前三种写法正确,最后一种写法错误。
示例
void test1(int arr[])
{
printf("%d\n", sizeof(arr));
}
void test2(char ch[])
{
printf("%d\n", sizeof(ch));
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(ch));
test1(arr);
test2(ch);
return 0;
}
输出结果为: 40 10 4 4.
对函数 test1和test2来说,计算的都是一个指针的大小,因此都是四个字节。
&&和 | |
逻辑操作符只关注真假。
&&相当于并且,只有左右两边均为真结果才为真。
| | 相当于或者,左右两边有一个为真则为真。
int main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++ && ++b && d++;
printf("a=%d\nb=%d\nc=%d\nd=%d\n", a, b, c, d);
return 0;
}
输出结果: 1 2 3 4
因为使用&&,只要有一方是0,则结果为假。又因为a为后置++,所以先使用。因此&&的左边是假,无论右边是什么,结果都为假,因此&&右边的式子不会计算了。 同理, ||左边为真,右边就不计算了。
条件操作符(三目操作符)
exp?exp2:exp3
exp是否为真?为真则计算表达式2的结果,并且表达式2的结果为整个表达式的结果。如果为假则计算表达式3的结果,并且表达式3的结果为整个表达式的结果。
补充:结构体指针->成员等价于 结构体对象.成员