C语言中移位操作符和位操作符&、|、^、~

移位操作符

<<  左移操作符

>>  右移操作符

移位操作符的操作数只能是正整数,不要移动负数位

因为数据在内存中存放的是补码,所以位操作符移动的是二进制位

<<  左移操作符

移位规则:左边抛弃、右边补0

正数

//正数
int main()
{
	int a = 6;
	int b = (a << 1);

 a    00000000 00000000 00000000 00000110
 b    00000000 00000000 00000000 00001100

	printf("%d\n", b);//12
	printf("%d\n", a);//6
	return 0;
}

负数 

//负数
int main()
{
	int a = -6;
	int b = (a << 1);
 
 a 原码10000000 00000000 00000000 00000110
   反码11111111 11111111 11111111 11111001
   补码11111111 11111111 11111111 11111010
 b 补码11111111 11111111 11111111 11110100
 b 原码10000000 00000000 00000000 00001100  
 
	printf("%d\n", b);//-12
	printf("%d\n", a);//-6
	return 0;
}

>>  右移操作符

右移操作符有逻辑右移和算术右移。

具体是右移运算符到底是算术右移还是逻辑右移是取决于编译器的,常见的编译器都是算术右移

正数

正数的逻辑右移和算术右移一样的,补位值都为0

//正数
int main()
{
	int num = 10;
	int n = num >> 1;

num  补码 00000000 00000000 00000000 00001010
n    补码 00000000 00000000 00000000 00000101

	printf("n = %d\n", n);//5
	printf("num = %d\n", num);//10
	return 0;
}

负数 

逻辑右移

左边用0填充,右边丢弃(没有分正负)

//负数
int main()
{
	int num = -10;
	int n = num >> 1;

num 原码 10000000 00000000 00000000 00001010
    反码 11111111 11111111 11111111 11110101
    补码 11111111 11111111 11111111 11110110
n   补码 01111111 11111111 11111111 11111011 
    原码 00000000 00000000 00000000 00000100
	printf("n = %d\n", n);//5
	printf("num = %d\n", num);//-10
	return 0;
}
算术右移

左边用原该值的符号位填充,右边丢弃

//负数
int main()
{
	int num = -10;
	int n = num >> 1;

num 原码 10000000 00000000 00000000 00001010
    反码 11111111 11111111 11111111 11110101
    补码 11111111 11111111 11111111 11110110
n   补码 11111111 11111111 11111111 11111011 
    原码 10000000 00000000 00000000 00000100
	printf("n = %d\n", n);//-5
	printf("num = %d\n", num);//-10
	return 0;
}
 m = ( left + right )/2
 m = left +(( right - left) >> 1 )
//经过观察可以发现 右移一位相当于除以二,
//右移运算符很少越界

 

位操作符:&、|、^、~

按位与:&

两个中有一个0就为0,两个同为1才是1。

int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;
	00000000 00000000 00000000 00000011    3的补码

    10000000 00000000 00000000 00000101   -5的原码
	11111111 11111111 11111111 11111010       反码
	11111111 11111111 11111111 11111011    -5的补码

	00000000 00000000 00000000 00000011     c 结果
	printf("%d\n", c);//3
	return 0;
}

按位或:|

两个中有一个1就是1,两个同时为0才是0.

int main()
{
	int a = 3;
	int b = -5;
	int c = a | b;

	00000000 00000000 00000000 00000011    3 补码

	10000000 00000000 00000000 00000101   -5 原码
	11111111 11111111 11111111 11111010
	11111111 11111111 11111111 11111011    -5 补码

	11111111 11111111 11111111 11111011     c 补码 结果
    10000000 00000000 00000000 00000101       原码 取反加一

	printf("%d\n", c);//-5
	return 0;
}

按位异或:^

相同为0,相异为1

int main()
{
	int a = 3;
	int b = -5;
	int c = a ^ b;

	00000000 00000000 00000000 00000011    3 补码

	10000000 00000000 00000000 00000101   -5 原码
	11111111 11111111 11111111 11111010   -5 反码
	11111111 11111111 11111111 11111011   -5 补码

	11111111 11111111 11111111 11111000    c 补码 结果
    10000000 00000000 00000000 00001000      原码 取反加一

	printf("%d\n", c);//-8
	return 0;
}

0与一个数按位异或还是这个数

两个相同数按位异或结果为0

a ^ a = 0 ;
a ^ 0 = 0 ;

这样可以解决不创建临时变量,实现两个数转换,可以参考我之前一篇文章 《实现两个数的交换》

按位取反:~

所有位置取反

int main()
{
	int a = 0;
	int c = ~a;

	00000000 00000000 00000000 00000000    a 原码
	11111111 11111111 11111111 11111111    a 补码

    10000000 00000000 00000000 00000000    c 补码
	10000000 00000000 00000000 00000001    c 原码

	printf("%d\n", c);//-1
	return 0;
}

 练习

练习:求一个整数存储在内存中的二进制中1的个数

求一个整数存储在内存中的二进制中1的个数
int main()
{
	int num = 10;//变成unsigned int可以解决负数问题
	int count = 0;
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("二进制中1的个数= %d\n", count);
	return 0;
}

int main()
{
	int num = -1;
	int i = 0;
	int count = 0;
	for (i = 0; i < 32; i++)
	{
		if (num & (1 << i)) //&有一个0就是0,全是1才是1
			count++;
	}
	printf("二进制中1的个数= %d\n", count);

	return 0;
}


n = n & (n-1)
 n   111101
n-1  111100
 n   111100
n-1  111011
 n   111000
n-1  110111
 n   110000
n-1  101111
 n   100000
n-1  011111
 n   000000


int main()
{
	int num = -1;
	int i = 0;
	int count = 0;
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	printf("二进制中1的个数= %d\n", count);
	return 0;
}

练习2:如何判断一个数是否是2的次方数

int main()
{
	int a = 0;
	scanf("%d", &a);
	if ((a & (a - 1))==0)
	{
		printf("%d就是二次方数",a);
	}
	else
	{
		printf("%d不是二次方数",a);
	}
	return 0;
}

练习3:将13二进制序列的第5位修改为1,然后再改回0

int main()
{
	int a = 13;
	a = a | (1 << 4); // | 有1就是1,两个0才为0
a 补码  00000000 00000000 00000000 00001101
1<<4    00000000 00000000 00000000 00010000
结果    00000000 00000000 00000000 00011101

	printf("a = %d\n", a);//29
	a = a & ~(1 << 4);// & 有0就是0,两个1才是1
 a 补码   00000000 00000000 00000000 00011101
~(1<<4)   11111111 11111111 11111111 11101111
   结果   00000000 00000000 00000000 00001101 


	printf("a = %d \n", a);//13
	return 0;
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值