c 语言 操作符详解

152 阅读4分钟

操作符

算数操作符

+  -  *  /  %

        int a1 = 3 / 5;// 0 商 0 余3
	// 如果想得到一个小数 需要 小数 除 小数

	float a = 3.0 / 5.0;
	printf("%f \n", a); // 0.600000
        
        // % 两端必须是整数 不能是小数
	int a = 7 % 3;// 7 除 3 商二 余数 1
	printf("%d", a);// 1

移位操作符

<< 左移操作符
>> 右移操作符
int main()
{
	int a = 2;
	int b = a << 1;
	// 把a的二进制位向左移动 一 位
        // 00000000 00000000 00000000 00000010
        // 00000000 00000000 00000000 00000100
	printf("%d", b);
	return 0;
}
// ---------------------------------------------------------------------------------
int main()
{
	int a = 10;
	int b = a >> 1;
	// 把a的二进制位向右移动 一 位
	// 00000000 00000000 00000000 00001010
	// 000000000 00000000 00000000 0000101
	printf("%d", b);// 5 a没有发生变化
	return 0;
}

// ---------------------------------------------------------------------------------

int main()
{
	int a = -1;
	// 当前的右移操作符 使用的算数右移 高位补的 1
	/*
		-1 在内存中,存放的二进制的补码
		整数的二进制表示形式有三种。
		原码:直接根据数值写出的二进制序列
		反码:原码的符号位不变 其它位按位取反
		补码:反码+1就是补码
                针对与负数的 原码 反码 补码
                而对于正整数 原码 反码 补码 相同

		原码:10000000 00000000 00000000 00000001
		反码:11111111 11111111 11111111 11111110
		补码:11111111 11111111 11111111 11111111

		如果是算数右移 右边丢弃 左边补原符号位。
			11111111 11111111 11111111 11111111
		如果是逻辑右移 右边丢弃 左边补 0。
			01111111 11111111 11111111 11111111
	*/
	int b = a >> 1;
	printf("%d", b);// -1
	return 0;
}

右移操作符:

  1. 算数右移: 右边丢弃,左边补原符号位
  2. 逻辑右移: 右边丢弃,左边补 0

正数无论是算数右移,还是逻辑右移,高位都补 0.

位操作符

    &:按位与  |:按位或  ^:按位异或
int main()
{
	int a = 3;
	int b = 5;
	// & 按(二进制)位与 
	// 对位的二进制按位与 
	// 对位二进制都是 1 按位与 1,
	// 对位二进制有一个 0 按位与 0
	int c = a & b;
	printf("%d", c);// 1
	// 00000000 00000000 00000000 00000011
	// 00000000 00000000 00000000 00000101
	// 00000000 00000000 00000000 00000001
	return 0;
}

// ---------------------------------------------------------------------------------

int main()
{
	int a = 3;
	int b = 5;
	// & 按(二进制)位或 
	// 对位的二进制按位与 
	// 对位二进制都是 有一个 1 就是 1,
	int c = a | b;
	printf("%d", c);// 7
	// 00000000 00000000 00000000 00000011
	// 00000000 00000000 00000000 00000101
	// 00000000 00000000 00000000 00000111
	return 0;
}

// ---------------------------------------------------------------------------------

任何两个相同的数字异或 一定是 0.
int main()
{
	int a = 3;
	int b = 5;
	// 按(二进制)位异或
	// 对应的二进制位 进行 异或
	// 相同为 0 相异为 1.
	int c = a ^ b;
	printf("%d", c);// 6
	// 00000000 00000000 00000000 00000011
	// 00000000 00000000 00000000 00000101   
	// 00000000 00000000 00000000 00000110   
										
	return 0;
}

二进制小练习

int main()
{
	// 求一个整数存储在 二进制内存中 1 的个数
	// 100 1110 1011
	int a = 1259;
	int x = 0; // 统计 1的个数
	int o = 32;// 循环32次
	while (0 < o)
	{
		int c = a & 1;// 相同为 1 ,不同为 0
		a = a >> 1; // 让 a 的二进制向右移动 高位补 0
		if (c == 1)
		{
			x++;
		}
		o--;
	}
	printf("%d", x);// 7 个1
										
	return 0;
}

赋值 复合操作符

  =  +=   /=   *=   -=   %=   >>=   <<=   &=   |=   ^=
  
  int a = 10;
  a += 100; 
  a = a + 100;
  // 相同

单目操作符

  1. 单目操作符只有一个操作数。
!:逻辑反操作, - 负值 , + 正值  , &取地址符 , sizefo() 操作数的类型长度,括号中的表达式不会参与运算(以 byte 为单位)

~ 对一个数的二进制按位取反 , -- 前置,后置 --  ,++ 前置 , 后置++

* 间接访问操作符(解引用操作符) , (类型)强制类型转换

小栗子

int main()
{
	int flag = 10;
	if (flag)
	{
		printf("真 \n");
	}
	if (!flag)// !真变假 假变真
	{
		printf("哈哈 \n");
	}
	else
	{
		printf("假 \n");
	}
	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = 10;

	printf("%d", sizeof(a));// 4 单位是 byte
	printf("%d", sizeof(int));// 4 类型也是一样
	// 对于变量名计算大小时 可以不用 ()
	// sizeof 是一个操作符 不是函数,函数不能省略 ()
	printf("%d", sizeof a); 

	int arr[10] = { 0 };
	printf("%d", sizeof(arr));// 单位 byte
	printf("%d", sizeof(int[10]));// 同样计算大小 

	short x = 5;
	int a = 10;
	printf("%d", sizeof(x = a + 2));// 2 短整型 x占两个byte
	// sizeof 中放的表达式是不参与计算的
        // 因为处理sizeof是在编译期间处理的,不会参与运算
	printf("%d", x);// 5

	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = -1;
	/*
		10000000 00000000 00000000 00000001 - 原码
		11111111 11111111 11111111 11111110 - 反码
		11111111 11111111 11111111 11111111 - 补码
		
		按位取反 ~ 包括符号位全部取反 0 变 1 ,1 变 0

		00000000 00000000 00000000 00000000
	*/
	int c = ~a;// 不会改变 a
	printf("%d", c);// 0
	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = 13;
	// 把a 的二进制中的第五位置变成 1 ;
	a = a | (1 << 4);
	// 把 a 的二进制中的位置5变为 0
	a = a & ~(1 << 4);
	printf("%d", a);// 13
	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = 10;
	int b = a++;// 后置++ 先使用 再++
	printf("%d \n", a);// 11
	printf("%d \n", b);// 10

	int c = ++a;// ++前置,先++, 后使用 
	printf("%d \n", a);// 12
	printf("%d \n", c);// 12
	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = 10;
	// & 取地址 
	// %p 打印地址 16进制
	printf("%p", &a);

	// pa就是来存放地址的 - pa是指针变量
	// *pa 解引用 间接访问 
	int* pa = &a;
	*pa = 20;// 把 a 改成 20.

	printf("%d", a);// a = 20
	return 0;
}

// -----------------------------------------------------------------

int main()
{
	int a = (float)3.14;// 类型转换
	printf("%d \n", a);// 3
	return 0;
}

结构成员访问操作符

  1. 结构体 ->
int main()
{
	struct Book
	{
		char name[20];
		char id[20];
		int pre;
	};
	// 结构体变量名.成员名
	struct Book b = { "c++","c191191",16 };
	printf("name => %s \n", b.name);
	printf("id => %s \n", b.id);
	printf("pre => %d \n", b.pre);

	// 引用 地址
	// 结构体指针 -> 成员名
	struct Book* pb = &b;
	printf("name => %s \n", pb->name);
	printf("id => %s \n", pb->id);
	printf("pre => %d \n", pb->pre);

	return 0;
}

隐式类型转换

5998.png

  • 整型提升是按照变量的数据类型符号位来提升的。
     
     int main()
{
	char a = 3;
	char b = 127;
	char c = a + b;
	// 发现 a , b都是char类型 都没达到一个int的大小
	// 这里就会发生整型提升
	printf("%d", c);// -126
	return 0;
}