C语言 位操作

c语言位操作中需要注意有:

  1. 位操作只针对整型和字符型数据

  2. 在右移操作中:对无符号数和有符号中的正数补 0;符号数中的负数,取决于所使用的系统:补 0 的称为“逻辑右移”,补 1 的称为“算术右移”。

循环移位的概念:

循环移位就是把从左边移出去的,补到右边去,或者从右边移出去的补到左边去,例如1000 0001循环右移以为得到:1100 0000,循环左移一位得到0000 0011

掩码的概念:

掩码就是掩盖住你不想让它出现的部分,例如在网络中的子网掩码,就是将网络中的子网内部IP划分屏蔽掉,例如需要判断两个IP是不是同一个网段的,就把它们分别和本网断的子网掩码换算成二进制,按位相与,得到要是同一个值就证明两个是同一个网段的。

生成掩码的三种方式和整数转化成二进制:

#include <stdio.h>
#pragma warning (disable:4996)

void itobs(int var);
void mask1(int *mask);
void mask2(int *mask);
void mask3(int *mask);

int main(void)
{
	int mask = 0;
	mask1(&mask);
	mask = 0;
	mask2(&mask);
	mask = 0;
	mask3(&mask);

	return 0;
}
void mask1(int *mask)
{
	*mask = (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0);
	//这样可以生成前面28个0,后面四个1的一个掩码
	itobs(*mask);
	printf("\n");

}
void mask2(int *mask)
{
	int n = 4;//表示要生成连续四个1的掩码,和mask1()方法结果一样
	while (n--){
		*mask |= 1 << n;
	}
	itobs(*mask);
	printf("\n");
}
void mask3(int *mask)
{
	int i = 0;
	for (i = 6; i > 2; i--){//可以用来生成固定位置是1的掩码
		*mask |= 1 << i;
	}
	itobs(*mask);
	printf("\n");
}
//利用位运算将整数转化为二进制表示
void itobs(int var)
{
	int i = 32;//整数在内存中占4个字节,也就是32位
	/*每次生成一个只有一位是1,其他位置是0的掩码和目标数按位与,
	就可以得到目标数的这个位置是0还是1,然后输出0或1就是目标数对应的二进制表示
	*/
	while (i--){
		if (var & 1 << i)
			printf("%d", 1);
		else
			printf("%d", 0);
		if (i % 8 == 0)//每八个分割显示,看起来比较好
			printf(" ");
	}
}

循环移位操作:

#include <stdio.h>
void circleMove(int *pdata, int n);
void itobs(int var);
int main(void)
{
    int data=7;
//    printf("请输入一个数字:\n");
//    scanf("%d",&data);
    itobs(data);
    printf("\n");
    //将7循环右移两位
    circleMove(&data,  -2);
    itobs(data);

    return 0;
}
//循环移位,当n>0的时候,当n<0的时候右移
//循环移位,就是把按理说移出去的那些补到另一头
void circleMove(int *pdata, int n)
{
    unsigned int data=*pdata;//使用unsigned处理,则发生右移后空出来的位置是统一补0的
    int temp=0;
    if(n>0)
        temp=n;
    else
        temp=-n;
    int mask=0;//掩码,被移调多少位,就要生成几位是1的掩码
    //这个while循环用来生成掩码
    while(temp--)
        mask |=1<<temp;
    if(n>0){//左移
        data = data<<n | (data>>(sizeof(data)*8-n)&mask);
        //前半部分处理左移,后半部分将本该移出去的先右移,用掩码保存起来,然后前后或就的到循环移位的数
    }
    else if(n<0){//右移
        temp=-n;
        data = data>>temp | ((mask&data)<<(sizeof(data)*8-temp));
    }
    *pdata=data;
}
void itobs(int var)
{
    int i=32;
    while(i--){
        if(var&1<<i)
            printf("%d",1);
        else
            printf("%d",0);
        if(i%8==0)
            printf(" ");
    }

}

利用位运算实现两个数交换值,不引入第三方变量和判断一个数是不是2的幂,也可以直接简单的使用加法,例如:

a=5,b=3;    a=a+b;    b=a-b;    a=a-b;但是着用方法存在溢出的危险,所以使用下列方法比较好

#include <stdio.h>
void swap(int *a, int *b);
void judgePower(int *num);
int main(void)
{
    int a=5,b=3;
    swap(&a,&b);
    printf("a=%d b=%d\n",a,b);

    int num=0;
    scanf("%d",&num);
    judgePower(&num);

    return 0;
}
//用按位异或交换两个数的值,值针对整型和字符型
void swap(int *a, int *b)
{
    *a =*a^*b;
    *b =*a^*b;
    *a =*a^*b;
}
//判断一个数是不是2的幂
void judgePower(int *num)
{
    /*
        原理:例如8的二进制表示是1000,它是2的幂,8-1=7=0111
        (1000)&(0111)=0所以,8是2的幂
    */
    if((*num)&(*num-1))
        printf("no");
    else
        printf("yes");
}
字符文件的 单个字符密钥异或加密、字符串密钥异或加密、循环移位加密:
#include <stdio.h>
#include <string.h>
#pragma warning(disable:4996)
void encrpty(char *secret, char key);//密钥为单个字符时的异或加密方法
void de_encrpty(char *secret, char key);//密钥为单个字符时的异或解密方法
void encrptyStr(char *secret, char *key);//密钥为字符串时的异或加密方法
void de_encrptyStr(char *secret, char *key);//密钥为字符串时的异或解密方法
void encode(char *secret);//对字符串进行循环移位加密
void decode(char *secret);//对字符串进行循环移位解密
int main(void)
{
	char source[100] = { 0 };
	printf("请输入需要加密的字符:\n");
	gets(source);
	//密钥为单个字符时的异或加密方法
	encrpty(source, 'o');
	printf("\n密钥为单个字符时加密后:\n%s\n", source);
	//密钥为单个字符时解密
	de_encrpty(source, 'o');
	printf("\n密钥为单个字符时解密后:\n%s\n", source);
	//密钥为字符串时加密,此处内置使用“love”字符串加密
	encrptyStr(source, "love");
	printf("\n密钥为字符串时加密后:\n%s\n", source);
	//密钥为字符串时解密
	de_encrptyStr(source, "love");
	printf("\n密钥为字符串时解密后:\n%s\n", source);
	//进行循环移位加密后
	encode(source);
	printf("\n进行循环移位加密后:\n%s\n", source);
	//进行循环移位解密后
	decode(source);
	printf("\n进行循环移位解密后:\n%s\n", source);
	return 0;
}
//秘钥是单个字符的加密方法
void encrpty(char *secret, char key)
{
	while (*secret)
	{
		if (*secret == key)
			/*当字符串中字符和密钥相同时跳过,避免数据截断
			  由于相同字符异或结果为0,放在字符串中就结束了字符串
			*/
			secret++;
		else{
			*secret ^= key;//与密钥异或
			secret++;
		}
	}
}
void de_encrpty(char *secret, char key)
{
	while (*secret)
	{
		if (*secret == key)
			secret++;
		else{
			*secret ^= key;//用异或来加密,自然用异或解密
			secret++;
		}
	}
}
//密钥是一个字符串的加密方法
void encrptyStr(char *secret, char *key)
{
	int klen = strlen(key);//密钥的长度
	int i = 0;//访问密钥的循环变量
	while (*secret != '\0')
	{
		if (*secret == key[i]){//若字符和密钥相同,则跳过,避免数据截断
			secret++;
			i++;
		}
		else{
			*secret ^= key[i];
			secret++;//向后推移目标串
			i++;//向后推移密钥串
		}
		if (i%klen == 0)//当密钥串遍历到头时,就把访问变量重置为0,从第一位重新开始
			i = 0;
	}
}
//密钥是一个字符串的解密方法,原理同加密
void de_encrptyStr(char *secret, char *key)
{
	int klen = strlen(key);
	int i = 0;
	while (*secret)
	{
		if (*secret == key[i]){
			secret++;
			i++;
		}
		else{
			*secret ^= key[i];
			secret++;
			i++;
		}
		if (i%klen == 0)
			i = 0;
	}
}
/*对字符串进行循环移位加密,这个不需要秘钥
原理是对每一个字符进行循环移位加密,例如字符的二进制形式是1000 0001,
则向右循环移位一位时的得到的结果是1100 0000
*/
void encode(char *secret)
{
	unsigned char temp = 0;
	while (*secret)
	{
		temp = *secret;
		temp = (temp & 1) << 7 | temp >> 1;
		//这里使用向右循环移动一位的方式,也可以是别的位数
		*secret = temp;
		secret++;
	}
}
//对字符串进行循环移位加密,是加密的逆过程
void decode(char *secret)
{
	unsigned char temp = 0;
	while (*secret)
	{
		temp = *secret;
		temp = (temp&(1 << 7)) >> 7 | temp << 1;
		*secret = temp;
		secret++;
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值