C语言学习笔记:16_位运算

/*
 * 16_位运算.c
 *
 *  Created on: 2015年7月6日
 *      Author: zhong
 */
#include 
#include 

/* 位运算:
 * 所谓的位运算是指以二进制位为对象的运算。
 * c语言中位运算符有:
 *  & 按位与
 *  | 按位或
 *  ^ 按位异或
 *  ~ 按位取反
 *  << 左移
 *  >> 右移
 *
 *	除了 ~ 按位取反运算符以外,均为二目运算符。 两边的运算对象只能是整型或者字符 型数据
 *----------------------------------------------------------------------------------------
 * 一:& 按位与 : 两个相应的二进制位都为1,则这位的结果值为1,否则为0; 0&0=0, 0&1=0; 1&0=0, 1&1=1
 *	例:
 *		00000111 (7)
 *	&	00000101 (5)
 *	——————————————————
 *		00000101 (5)
 *	因此:7&5=5。如果参加&运算的是负数,则以袚形式表示 为二进制数,然后按位进行‘与’操作
 *	注意: &&与&的区别, &&是逻辑与运算符,7&&5值为1,因为非0数为真,真真得真=1;
 *
 *	按位与‘&’的用途:
 *	 1:将一个数‘清零’
 *		只要找一个二进制数,原来的数中为1的位,新数中相应的位为0进行&运算,即可达到清零目的。
 *		任何数与0 按位与操作,者为0; 因为两个二进制位,只要有一个是0,其为0;
 *	 2:取一个数中某些指定位:
 *	 		如:  取300四个字节中的最低一个字节
 *	 		00000000 00000000 00000001 00101100 (300)
 *	 		00000000 00000000 00000000 11111111 (255)
 *	 		————————————————————————————————————————————————————————
 *			00000000 00000000 00000000 00101100  (44)
 *------------------------------------------------------------------------------------------
 * 二:| 按位或 : 两个相应的二进制位只要一个为1,则这位的结果值为1;只有两个为0时,才为0; 0&0=0, 0&1=1; 1&0=1, 1&1=1
 *		00000111 (7)
 *	|	00000101 (5)
 *	——————————————————
 *		00000111 (7)
 *--------------------------------------------------------------------------------------------
 * 三: '^' 异或运算符: 参加运算的两个 二进制位异号,则两位相同时为假(0),不同是为真(1)  即  0^0=0; 0^1=1, 1^0=1, 1^1=0
 *		  异或的意思是判断两个相应 的位值是否0 ‘异’,为‘异’就取真(1),否则为假(0)
 *		00000111 (7)
 *	^	00000101 (5)
 *	——————————————————
 *		00000010 (2)
 *	应用 :
 * 1、将二进制各位'取反'
 *		00111010
 *	^	11111111
 *	————————————————
 *	    11000101
 * 2、与0相^,保留原直
 *
 * 3、交换两个值,不用临时变量
 *   a=a^b; b=b^a; a=a^b; 这样就可以交换两个变量的值了
 *		a=7,b=5;
 *		00000111 (7)
 *	^	00000101 (5)
 *	——————————————————
 *		00000010 (2)  a=a^b=2
 *	^	00000101 (5)
 *	——————————————————
 *		00000111 (7)  b=a^b=7;(和b=b^a意思一样的)
 *	^	00000010 (2)
 *  ——————————————————
 *  	00000101 (5)  a=b^a=5;(和a=a^b意思是一样的)
 * 4、一个数和自己异或,结果为0
 * 5、两个数异或顺序可以互换的,结果一样。 如9^5^9= 9^9^5 =0^5 =5;
 *
 *----------------------------------------------------------------------------------------
 * 四:~ 是一个单目运算符,用来对一个二进制数按位取反,即0变1,1变0
 * 	~	00000111 (7)
 * 	——————————————————
 * 		11111000 (248)  ~7=248
 *
 *----------------------------------------------------------------------------------------
 * 五:左移运算:<< 用来将一个数的各二进制位全部左移若干位,高位左移溢出时,舍去。右边补0
 * 例如  a=15  将a左移2位 a=a<<2  =60;
 *
 *   <<2    00 00 11 11  (15)
 * 	———————————————————————
 *     (00) 00 11 11(00) (60)
 *     溢出舍去                        右补0
 *
 *   左移运算的特点: 一个数左移1位相当于这个数乘以2,左移2位相当于这个数乘以2^2=4。(前提条件是,高位溢出的位不能是1,只能是0)
 *   			左移比乘法运算快,所以编译程序自动将乘2的运算左移一位为实现,将乘以2^n为左移n位。
 *
 *	面试题:用最有效率的方法算出2乘以8等於几
 *			2<<3; 相当于2*2^3=2*8
 *
 *----------------------------------------------------------------------------------------
 * 六:右移运算 >>表示将二进制位右移n位,移到右端的低位被舍弃,对无符号数,高位补0。
 *   例如:a=017; a=a>>2;
 *  >>2 	00 00 11 11                (17)
 *  ———————————————————
 *  	  (00) 00 00 11 (11) (3)
 *  	      左补0           此2位舍弃
 *	右移运算的特点: 和左移刚好相反啦。一个数右移1位相当于这个数除以2,右移n位相当于除以2^n次方法。
 *	在右移时,要注意符号位的问题。对无符号数,右移左边高位补0;对于有符号数据,如果原来符号位为0(正数),则左边补0。
 *						如果符号位原来为1(负数) ,则左移补0还是1,要取决于所用的计算机系统。有的补0,有的补1。
 *							补0的称为"逻辑右移"不考虑符号问题。补1的称为"算术右移"保持原来符号
 *----------------------------------------------------------------------------------------
 *七:位运算赋值运算符:即位运算与赋值运算符组合 :&= ;|= ;>>= ;<<=  ;^=
 *
 *	作用和 *= ,+=是一样的。 比如 a&=b,相当于a=a&b;
 *
 *
 *若两个不同长度的数据进行位运算,系统会将二者按右端对齐,右侧补0;
 *
 *----------------------------------------------------------------------------------------
 */
//位运算 & ‘与’
void bit_arith_and() {
	int a = 7, b = 5;
	printf("7&5=%d\n", a & b); //output:5
	a = 300, b = 255;
	printf("300&255=%d\n", a & b); //output:44
}
//位运算 | ‘或’
void bit_arith_or() {
	int a = 7, b = 5;
	printf("7|5=%d\n", a | b); //output:7
	a = 300, b = 255;
	printf("300|255=%d\n", a | b); //output:511
}
//位运算 ^ ‘异或’
void bit_arith_and_or() {
	int a = 7, b = 5;
	printf("7^5=%d\n", a ^ b); //output:2
}
//4:使用^(异或)算法,交换两个变量的值
void use_or_swap_number() {
	int a = 10, b = 11;
	a = a ^ b; //1
	b = b ^ a; //11-1=10
//	b=a^b; //和上面哪句一样的
	a = a ^ b; // 1+10=11
	printf("使用^(异或)算法交换两个数:a=%d,b=%d\n", a, b);
}
//左移
void left_shift() {
	printf("%d", 2 << 2); //2*2^2=8
}
//右移
void right_shift() {
	printf("%d", 8 >> 2); //8/2^2=2;
}

//用按位与&判断一个数是奇数还是偶数
void exercise_1() {
	/**
	 *奇数与偶数的特征:
	 * 1111 (15)
	 * 1001 (9)
	 *
	 * 1110 (14)
	 * 1010 (10)
	 *
	 * 根据上面可发现:右数的最后一位都是1,偶数最后一位都是0;
	 * 解题思路: 只要用这个数&1 就可以取出 最后一位,如果是1,就是奇数。是0就是偶数
	 * 1111
	 * 0001 (&1)
	 * ————
	 * 0001 这样就取出了最后一位
	 *
	 */

	int a = 15;
	int b = 20;
	a & 1 == 1 ? printf("%d是奇数\n", a) : printf("%d是偶数\n", a); //使用三目运算符
	b & 1 == 1 ? printf("%d是奇数\n", b) : printf("%d是偶数\n", b); //使用三目运算符

}

//用位运算输出一个十进制数的二进制形式
void printf_bin(int number) {
//	int count = sizeof(number)*8-1; //获得这个数的位数
	int count = (sizeof(number)<<3)-1; //获得这个数的位数  左移n位相当于*2的n次方。   <<3==*8; 由于算术运算符优先级高于位运算符,所以 要加()

	while (count >= 0) {
		int n_ = number >> count & 1; //第一次左移31位&1取得这一位数。。。。。。
		printf("%d", n_);
		if (count % 4 == 0) { //四位空一格:0000 0000 0000 0000 0000 0000 0000 1111
			printf(" ");
		}
		count--;
	}
	printf("\n");
}

int main() {
//	bit_arith_and();
//	bit_arith_or();
//	bit_arith_and_or();
//	use_or_swap_number();
//	left_shift();
//	right_shift();
//	exercise_1();
	printf_bin(15); //output:0000 0000 0000 0000 0000 0000 0000 1111

	return 0;
}

你可能感兴趣的:(C语言)