1、移位操作符
整数的二进制表示形式:原码、反码、补码
int main()
{
int a = 15;
//十进制的15转化为二进制为 1111
//1个整型是4个字节 = 32个bit位
//00000000000000000000000000001111 --->原码、反码、补码相同
//二进制的最高位为符号位,符号位为0,表示正数,符号位为1,表示负数
int b = -15;
//10000000000000000000000000001111 --->原码
//11111111111111111111111111110000 --->反码(原码符号位不变,其他位按位取反)
//11111111111111111111111111110001 --->补码 (反码+1)
//整数在内存中存储的是补码
//计算的时候也是是用补码
return 0;
}
移位移动的是补码的二进序列
1.1右移操作符
①算术右移:右边丢弃,左边补原来的符号位(正数补0,负数补1)
②逻辑右移:右边丢弃,左边直接补0
C语言没有明确规定是算术右移还是逻辑右移,一般编译器上采用的都是算数右移
1.2左移操作符
移位规则:左边抛弃,右边补0
注意:
对于移位运算符,不要移动负数位,属于标准未定义行为
2、位操作符
位操作符有
& 按位与
int main()
{
int a = 0;
//0000000000000000000000000011 --补码
int b = -5;
//1000000000000000000000000101 --原码
//1111111111111111111111111010 --反码
//1111111111111111111111111011 --补码
int c = a & b;
// & 运算规则:对应二进制位有0则为0,两个同时为1,才为1
//a -- 0000000000000000000000000011 --补码
//b -- 1111111111111111111111111011 --补码
//c -- 0000000000000000000000000011 --补码
return 0;
}
这里求出c的补码,因为符号位为0,是正数,所以原反补相同,从而的到c的值为3
| 按位或
int main()
{
int a = 3;
//0000000000000000000000000011 --补码
int b = -5;
//1000000000000000000000000101 --原码
//1111111111111111111111111010 --反码
//1111111111111111111111111011 --补码
int c = a | b;
// | 运算规则:对应二进制位有1则为1,两个同时为0,才为0
//a -- 0000000000000000000000000011 --补码
//b -- 1111111111111111111111111011 --补码
//c -- 1111111111111111111111111011 --补码
//c -- 1111111111111111111111111010 --反码
//c -- 1000000000000000000000000101 --原码 十进制为 -5
printf("%d\n", c);
return 0;
}
^ 按位异或
int main()
{
int a = 3;
//0000000000000000000000000011 --补码
int b = -5;
//1000000000000000000000000101 --原码
//1111111111111111111111111010 --反码
//1111111111111111111111111011 --补码
int c = a | b;
// ^ 运算规则:对应二进制位相同为0,相异为1
//a -- 0000000000000000000000000011 --补码
//b -- 1111111111111111111111111011 --补码
//c -- 1111111111111111111111111000 --补码
//c -- 1111111111111111111111110111 --反码
//c -- 1000000000000000000000001000 --原码 十进制为 -8
printf("%d\n", c);
return 0;
}
练习:
编写代码实现:求一个整数存储在内存中的二进制中1的个数
int main()
{
int n = 15;
int count = 0;
while (n)
{
if ((n & 1) == 1)
{
count++;
}
n >>= 1;
}
printf("%d\n", count);
return 0;
}
运行结果:
3、单目操作符sizeof和数组
sizeof是一个操作符,不是函数,计算的是类型创建变量的大小,单位是字节
#include <stdio.h>
void test1(int arr[])//int * 的
{
printf("%d\n", sizeof(arr));//(3)
}
void test2(char ch[])//char * 的指针
{
printf("%d\n", sizeof(ch));//(4)
}
int main()
{
int arr[10] = { 0 };
char ch[10] = { 0 };
printf("%d\n", sizeof(arr));//(1)
printf("%d\n", sizeof(ch));//(2)
test1(arr);
test2(ch);
return 0;
}
运行结果
数组传参之后其实变成了指针
4、结构体成员
访问一个结构体的成员
. 结构体.成员名
-> 结构体指针->成员名
struct Book
{
char name[30];//成员
char author[20];
float price;
};
void Print(struct Book * p)
{
printf("%s %s %.1f\n", (*p).name, (*p).author, (*p).price);
printf("%s %s %.1f\n", p->name, p->author, p->price);
//->
//结构指针->成员名
}
int main()
{
struct Book b1 = { "C语言第一课", "鹏哥", 66.6f };//书
struct Book b2 = { "数据结构第一课", "杭哥", 88.8f };//书
Print(&b1);
Print(&b2);
//printf("%s %s %.1f\n", b1.name, b1.author, b1.price);
//printf("%s %s %.1f\n", b2.name, b2.author, b2.price);
//结构体变量.成员名
return 0;
}