C语言 位操作
c语言位操作中需要注意有:
-
位操作只针对整型和字符型数据
-
在右移操作中:对无符号数和有符号中的正数补 0;符号数中的负数,取决于所使用的系统:补 0 的称为“逻辑右移”,补 1 的称为“算术右移”。
循环移位的概念:
循环移位就是把从左边移出去的,补到右边去,或者从右边移出去的补到左边去,例如1000 0001循环右移以为得到:1100 0000,循环左移一位得到0000 0011
掩码的概念:
掩码就是掩盖住你不想让它出现的部分,例如在网络中的子网掩码,就是将网络中的子网内部IP划分屏蔽掉,例如需要判断两个IP是不是同一个网段的,就把它们分别和本网断的子网掩码换算成二进制,按位相与,得到要是同一个值就证明两个是同一个网段的。
生成掩码的三种方式和整数转化成二进制:
1 #include <stdio.h> 2 #pragma warning (disable:4996) 3 4 void itobs(int var); 5 void mask1(int *mask); 6 void mask2(int *mask); 7 void mask3(int *mask); 8 9 int main(void) 10 { 11 int mask = 0; 12 mask1(&mask); 13 mask = 0; 14 mask2(&mask); 15 mask = 0; 16 mask3(&mask); 17 18 return 0; 19 } 20 void mask1(int *mask) 21 { 22 *mask = (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0); 23 //这样可以生成前面28个0,后面四个1的一个掩码 24 itobs(*mask); 25 printf("\n"); 26 27 } 28 void mask2(int *mask) 29 { 30 int n = 4;//表示要生成连续四个1的掩码,和mask1()方法结果一样 31 while (n--){ 32 *mask |= 1 << n; 33 } 34 itobs(*mask); 35 printf("\n"); 36 } 37 void mask3(int *mask) 38 { 39 int i = 0; 40 for (i = 6; i > 2; i--){//可以用来生成固定位置是1的掩码 41 *mask |= 1 << i; 42 } 43 itobs(*mask); 44 printf("\n"); 45 } 46 //利用位运算将整数转化为二进制表示 47 void itobs(int var) 48 { 49 int i = 32;//整数在内存中占4个字节,也就是32位 50 /*每次生成一个只有一位是1,其他位置是0的掩码和目标数按位与, 51 就可以得到目标数的这个位置是0还是1,然后输出0或1就是目标数对应的二进制表示 52 */ 53 while (i--){ 54 if (var & 1 << i) 55 printf("%d", 1); 56 else 57 printf("%d", 0); 58 if (i % 8 == 0)//每八个分割显示,看起来比较好 59 printf(" "); 60 } 61 }
循环移位操作:
1 #include <stdio.h> 2 void circleMove(int *pdata, int n); 3 void itobs(int var); 4 int main(void) 5 { 6 int data=7; 7 // printf("请输入一个数字:\n"); 8 // scanf("%d",&data); 9 itobs(data); 10 printf("\n"); 11 //将7循环右移两位 12 circleMove(&data, -2); 13 itobs(data); 14 15 return 0; 16 } 17 //循环移位,当n>0的时候,当n<0的时候右移 18 //循环移位,就是把按理说移出去的那些补到另一头 19 void circleMove(int *pdata, int n) 20 { 21 unsigned int data=*pdata;//使用unsigned处理,则发生右移后空出来的位置是统一补0的 22 int temp=0; 23 if(n>0) 24 temp=n; 25 else 26 temp=-n; 27 int mask=0;//掩码,被移调多少位,就要生成几位是1的掩码 28 //这个while循环用来生成掩码 29 while(temp--) 30 mask |=1<<temp; 31 if(n>0){//左移 32 data = data<<n | (data>>(sizeof(data)*8-n)&mask); 33 //前半部分处理左移,后半部分将本该移出去的先右移,用掩码保存起来,然后前后或就的到循环移位的数 34 } 35 else if(n<0){//右移 36 temp=-n; 37 data = data>>temp | ((mask&data)<<(sizeof(data)*8-temp)); 38 } 39 *pdata=data; 40 } 41 void itobs(int var) 42 { 43 int i=32; 44 while(i--){ 45 if(var&1<<i) 46 printf("%d",1); 47 else 48 printf("%d",0); 49 if(i%8==0) 50 printf(" "); 51 } 52 53 }
利用位运算实现两个数交换值,不引入第三方变量和判断一个数是不是2的幂,也可以直接简单的使用加法,例如:
a=5,b=3; a=a+b; b=a-b; a=a-b;但是着用方法存在溢出的危险,所以使用下列方法比较好
1 #include <stdio.h> 2 void swap(int *a, int *b); 3 void judgePower(int *num); 4 int main(void) 5 { 6 int a=5,b=3; 7 swap(&a,&b); 8 printf("a=%d b=%d\n",a,b); 9 10 int num=0; 11 scanf("%d",&num); 12 judgePower(&num); 13 14 return 0; 15 } 16 //用按位异或交换两个数的值,值针对整型和字符型 17 void swap(int *a, int *b) 18 { 19 *a =*a^*b; 20 *b =*a^*b; 21 *a =*a^*b; 22 } 23 //判断一个数是不是2的幂 24 void judgePower(int *num) 25 { 26 /* 27 原理:例如8的二进制表示是1000,它是2的幂,8-1=7=0111 28 (1000)&(0111)=0所以,8是2的幂 29 */ 30 if((*num)&(*num-1)) 31 printf("no"); 32 else 33 printf("yes"); 34 }
字符文件的 单个字符密钥异或加密、字符串密钥异或加密、循环移位加密:
1 #include <stdio.h> 2 #include <string.h> 3 #pragma warning(disable:4996) 4 void encrpty(char *secret, char key);//密钥为单个字符时的异或加密方法 5 void de_encrpty(char *secret, char key);//密钥为单个字符时的异或解密方法 6 void encrptyStr(char *secret, char *key);//密钥为字符串时的异或加密方法 7 void de_encrptyStr(char *secret, char *key);//密钥为字符串时的异或解密方法 8 void encode(char *secret);//对字符串进行循环移位加密 9 void decode(char *secret);//对字符串进行循环移位解密 10 int main(void) 11 { 12 char source[100] = { 0 }; 13 printf("请输入需要加密的字符:\n"); 14 gets(source); 15 //密钥为单个字符时的异或加密方法 16 encrpty(source, 'o'); 17 printf("\n密钥为单个字符时加密后:\n%s\n", source); 18 //密钥为单个字符时解密 19 de_encrpty(source, 'o'); 20 printf("\n密钥为单个字符时解密后:\n%s\n", source); 21 //密钥为字符串时加密,此处内置使用“love”字符串加密 22 encrptyStr(source, "love"); 23 printf("\n密钥为字符串时加密后:\n%s\n", source); 24 //密钥为字符串时解密 25 de_encrptyStr(source, "love"); 26 printf("\n密钥为字符串时解密后:\n%s\n", source); 27 //进行循环移位加密后 28 encode(source); 29 printf("\n进行循环移位加密后:\n%s\n", source); 30 //进行循环移位解密后 31 decode(source); 32 printf("\n进行循环移位解密后:\n%s\n", source); 33 return 0; 34 } 35 //秘钥是单个字符的加密方法 36 void encrpty(char *secret, char key) 37 { 38 while (*secret) 39 { 40 if (*secret == key) 41 /*当字符串中字符和密钥相同时跳过,避免数据截断 42 由于相同字符异或结果为0,放在字符串中就结束了字符串 43 */ 44 secret++; 45 else{ 46 *secret ^= key;//与密钥异或 47 secret++; 48 } 49 } 50 } 51 void de_encrpty(char *secret, char key) 52 { 53 while (*secret) 54 { 55 if (*secret == key) 56 secret++; 57 else{ 58 *secret ^= key;//用异或来加密,自然用异或解密 59 secret++; 60 } 61 } 62 } 63 //密钥是一个字符串的加密方法 64 void encrptyStr(char *secret, char *key) 65 { 66 int klen = strlen(key);//密钥的长度 67 int i = 0;//访问密钥的循环变量 68 while (*secret != '\0') 69 { 70 if (*secret == key[i]){//若字符和密钥相同,则跳过,避免数据截断 71 secret++; 72 i++; 73 } 74 else{ 75 *secret ^= key[i]; 76 secret++;//向后推移目标串 77 i++;//向后推移密钥串 78 } 79 if (i%klen == 0)//当密钥串遍历到头时,就把访问变量重置为0,从第一位重新开始 80 i = 0; 81 } 82 } 83 //密钥是一个字符串的解密方法,原理同加密 84 void de_encrptyStr(char *secret, char *key) 85 { 86 int klen = strlen(key); 87 int i = 0; 88 while (*secret) 89 { 90 if (*secret == key[i]){ 91 secret++; 92 i++; 93 } 94 else{ 95 *secret ^= key[i]; 96 secret++; 97 i++; 98 } 99 if (i%klen == 0) 100 i = 0; 101 } 102 } 103 /*对字符串进行循环移位加密,这个不需要秘钥 104 原理是对每一个字符进行循环移位加密,例如字符的二进制形式是1000 0001, 105 则向右循环移位一位时的得到的结果是1100 0000 106 */ 107 void encode(char *secret) 108 { 109 unsigned char temp = 0; 110 while (*secret) 111 { 112 temp = *secret; 113 temp = (temp & 1) << 7 | temp >> 1; 114 //这里使用向右循环移动一位的方式,也可以是别的位数 115 *secret = temp; 116 secret++; 117 } 118 } 119 //对字符串进行循环移位加密,是加密的逆过程 120 void decode(char *secret) 121 { 122 unsigned char temp = 0; 123 while (*secret) 124 { 125 temp = *secret; 126 temp = (temp&(1 << 7)) >> 7 | temp << 1; 127 *secret = temp; 128 secret++; 129 } 130 }