• 左移操作符:<<

左边丢弃,右边补0

1
2
3
4
5
6
7
8
int main()
{
int a = 2;
//把a的二进制位向左移动一位
int b = a << 1;
printf("b = %d\n", b);//输出为4
return 0;
}

  • 右移操作符:>>

1.算术右移:右边丢弃,左边补原符号位

2.逻辑右移:右边丢弃,左边补0

1
2
3
4
5
6
7
#include<stdio.h>
int main()
{
int a = -3;
int b = a >> 1;
printf("%d", b); //输出为-2
}

负数在内存中存放的是二进制的补码。

原码:直接根据数值写出的二进制序列

反码:符号位不变,其他位按位取反

补码:反码+1

以-3为例:

原码:10000000000000000000000000000011

反码:11111111111111111111111111111100

补码:11111111111111111111111111111101


  • 异或:^

同为0,异为1

练习:a=3,b=5,交换a、b两个数的值

方法1:创建中间变量

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
int temp = 0;
temp = a;
a = b;
b = temp;
printf("a=%d,b=%d", a, b); //a=5,b=3
}

方法2:加减运算(数值太大可能溢出)

1
2
3
4
5
6
7
8
9
int main()
{
int a = 3;
int b = 5;
a = a + b;
b = a - b;
a = a - b;
printf("a=%d,b=%d", a, b);
}

方法三:异或运算

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main()
{
int a = 3;
int b = 5;
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("a=%d,b=%d", a,b);
}

同值异或值为0,任何值异或0都是值本身。a^a=0 0^a=a


单目运算符:

sizeof也是单目运算符,可以计算变量所占空间的大小,单位是字节。

1
2
3
4
5
6
int a = 5;
int arr[5] = { 0 };
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof(int));//4
printf("%d\n", sizeof(arr));//20 sizeof(数组名)
printf("%d\n", sizeof(int [5]));//20 sizeof(数组类型)

sizeof(),括号内可以说变量名,也可以是变量类型,如果是变量名可以去掉小括号,如sizeof a

思考一下下面这段代码,两次输出是什么?

1
2
3
4
short s = 5;
int a = 10;
printf("%d\n", sizeof(s = a + 2));
printf("%d\n", s);

输出结果是2、5。s的类型是short,sizeof(short)结果必然是2,而sizeof括号里的表达式不参与运算,所以s仍未5。

前置和后置:

1
2
3
4
int a = 10;
int b = a++;//后置++,先使用,再++
printf("%d\n", a);//11
printf("%d\n", b);//10
1
2
3
4
int a = 10;
int b = ++a;//前置++,先++,后使用
printf("%d\n", a);//11
printf("%d\n", b);//11

指针大小永远是4字节或8字节

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void test1(int arr[])//相当于int *arr
{
printf("%d\n", sizeof(arr));//4
}
void test2(char ch[])//相当于char *arr
{
printf("%d\n", sizeof(ch));//4
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));//40
printf("%d\n", sizeof(ch));//10
test1(arr);
test2(arr);
return 0;
}

结构成员访问操作符:. ->

. 结构体.成员名

-> 结构体指针->成员名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
struct students
{ //结构体的成员(变量)
char name[10];
int age;

};
int main()
{
struct students a = { "胖虎",20 };
struct students *pb = &a; //说明pb是struct students类型的指针
//结构体变量名.成员名
printf("姓名:%s,年龄:%d\n", a.name,a.age);
//结构体指针->成员名
printf("姓名:%s,年龄:%d", pb->name,pb->age);
}

image-20211024164538183


整型提升:

C的整型算术运算总是至少以缺省整型类型的精度来进行的。 为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int main()
{
char a = 3;
//0000000000000000000000000000011 (int a)
//00000011 --a
//0000000000000000000000000000011 (a的整型提升)
char b = 127;
//0000000000000000000000001111111 (int b)
//01111111 --b
//0000000000000000000000001111111 (b的整型提升)
//0000000000000000000000010000010 int c
//10000010 --c
//1111111111111111111111110000010 补码 (c的整型提升)
//1000000000000000000000001111101 反码
//1000000000000000000000001111110 原码
char c = a + b;
printf("%d", c);
return 0;
}

整形提升是按照变量的数据类型的符号位来提升的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//负数的整形提升
char c1 = -1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果是:
11111111111111111111111111111111
//正数的整形提升
char c2 = 1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为 char 为有符号的 char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结果是:
00000000000000000000000000000001
//无符号整形提升,高位补0

总结:char和short类型,在参与表达式运算时达不到整型长度,会发生整型提升。