五、位运算
五、位运算
位运算主要计算内存中每个小格的数据
1、输出二进制内容
头文件调用 | 语法 | 示例 |
---|---|---|
include <bitser> | std::bitset<要显示的二进制位数>(要显示的变量) | std::cout << std::bitset<16>(a); |
//二进制内容输出
#include <iostream>
#include <bitset>
int main()
{
int a{ 0b100000001100 };
std::cout << std::bitset<16>(a);
}
2、左移、右移
1)左移:左移相当于*2,即a*(2n),如a左移2位,即a*(22)
#include <iostream>
#include <bitset>
int main()
{
int a{ 0b100000001100 };
std::cout <<"左移8位前:" << std::bitset<16>(a) << std::endl;
a <<= 8; //a=a<<8
std::cout <<"左移8位前:"<< std::bitset<16>(a)<<std::endl;
}
2)右移:右移相当于/2,即a/(2n),如a右移2位,即a/(22)
#include <iostream>
#include <bitset>
int main()
{
int a{ 0b100000001100 };
std::cout <<"左移8位前:" << std::bitset<16>(a) << std::endl;
a <<= 8; //a=a<<8 左移8位
std::cout <<"左移8位前:"<< std::bitset<16>(a)<<std::endl;
a >>= 8; //右移8位
std::cout << "右移8位后:" << std::bitset<16>(a) << std::endl;
}
注:位运算左右移,正数补0,负数补1
#include <iostream>
#include <bitset>
int main()
{
//int a{ 0b100000001100 };
int a{ -3 };
std::cout << a << std::endl;
std::cout << "左移8位前:" << std::bitset<16>(a) << std::endl;
a <<= 8; //a=a<<8 左移8位
std::cout << "左移8位前:" << std::bitset<16>(a) << std::endl;
a >>= 8; //右移8位
std::cout << "右移8位后:" << std::bitset<16>(a) << std::endl;
}
注:在某些CPU下,*2操作会自动转化为位运算,因位运算运算较快。位运算时最好用unsigned类型,因为unsigned类型,在任何CPU下一定是补1,而int类型可能补0或者补1
3、求反运算、与运算
1)求反运算(~):按位取反,0变1、1便0
#include <iostream>
#include <bitset>
int main()
{
int test{ 0xFFFF };
std::cout << "求反之前:"<< std::bitset<32>(test) << std::endl;
test = ~test; //求反
std::cout << "求反之后:"<< std::bitset<32>(test) << std::endl;
}
2)与运算(&):见0为0,一般用于保留高位
//获取地址高位
#include <iostream>
#include <bitset>
int main()
{
using std::showbase; //显示八进制和十六进制前缀
int test{ 0x2833 };
std::cout << "正常 输出:" << std::hex<<showbase<<test << std::endl;
test = test & 0xFF00; //与运算
std::cout << "与运算之后:" << std::hex <<showbase<<test<< std::endl;
}
4、或运算、异或运算
1)或运算( | ):见1则为1,常用于,只要灯没打开,就把它打开
#include <iostream>
#include <bitset>
//直接将0x2833,调整位0xFF33,即将高位写满
int main()
{
using std::showbase; //显示八进制和十六进制前缀
int test{ 0x2833 };
std::cout << "正常 输出:" << std::hex << showbase << test << std::endl;
test = test | 0xFF00; //或运算
std::cout << "或运算之后:" << std::hex << showbase << test << std::endl;
}
2)异或运算( ^ ):相同为0,不同为1
#include <iostream>
#include <bitset>
int main()
{
using std::showbase; //显示八进制和十六进制前缀
int test{ 0x2833 };
std::cout << "正常 输出:" << std::hex << showbase << test << std::endl;
test = test ^ 0xFF00; //异或运算
std::cout << "或运算之后:" << std::hex << showbase << test << std::endl;
}
5、案例:完善游戏激活码,需求如下
1)我们收到了一位用户的激活请求,用户的硬件码为:930529060092641281,我们需要回馈给用户一个激活码,该激活码是N组16进制数,每组4位。例如:192E-987E-675E-3E98-9172-972E。设计我们游戏中的激活部分程序,通过输出该激活码可以激活用户的游戏,
2)激活码中包含了16个等级的初始金币礼包,计算方式为:等级*等级*10000,包含了用户初始幸运属性,分为16个等级,这将影响到用户日后游戏中的爆率。
3)我们还赠送了三件装备,分别是武器、护甲、首饰、这三件装备等级分为16个阶,适用不同的等级阶段,最高可以强化至16,比如武器,可以是16阶强化+16。根据激活码对用户初始装备进行强化
4)同时要求我们的激活码还具备一定的防伪能力,能够与用户的硬件码相呼应,即在其他的电脑中不能使用(我们假设用户提交的硬件码是唯一的)
#include <iostream>
int main()
{
long long mcode{ 930529060092641281 }; //用户提供的硬件码
long long test_code{ (int)0xF2349876EF56CA24LL }; //内置测试码
long long end = mcode ^ test_code; //第一次异或,计算出激活码
//std::cout << end << std::endl;
std::cout << "给予用户的激活码为:"<< std::hex << end << "2556595f" << std::endl; //给用户的激活码,f316 18bf ef56 ca25 2556 595f
//模拟用户输入激活码,1、2、3、4组代表机器码,5、6组代表用户初始属性
unsigned short in_code1, in_code2, in_code3, in_code4, in_code5, in_code6;
std::cin >> std::hex; //因激活码为16进制数,因此切换输入流为16进制
std::cout << "请输入第一组激活码:";
std::cin >> in_code1;
std::cout << "请输入第二组激活码:";
std::cin >> in_code2;
std::cout << "请输入第三组激活码:";
std::cin >> in_code3;
std::cout << "请输入第四组激活码:";
std::cin >> in_code4;
std::cout << "请输入第五组激活码:";
std::cin >> in_code5;
std::cout << "请输入第六组激活码:";
std::cin >> in_code6;
//将用户输入的激活码,按照每组进行取出
long long end_final{};
long long ls{}; //临时变量
ls = in_code1;
ls <<= 48; //获取到第一组激活码
//std::cout << ls << std::endl; //f316000000000000
end_final |= ls;
ls = in_code2;
ls <<= 32;
end_final |= ls;
//std::cout << ls << std::endl; //18bf00000000
ls = in_code3;
ls <<= 16;
//std::cout << ls << std::endl; //ef560000
end_final |= ls;
end_final |= in_code4;
std::cout <<"取出的用户激活码为:"<< end_final << std::endl; //将用户输入的激活码,完整取出
long long mcode_calc = end_final ^ test_code; //将用户输入的激活码和游戏内置测试码进行比较,若计算结果不是用户机器码,则不予激活
std::cout << "计算出的用户机器码为:"<<std::dec << mcode_calc << std::endl;
if (mcode_calc == mcode)
{
std::cout << "你输入的激活码正确,游戏激活成功!!!\n";
//f316 18bf ef56 ca25 2556 595f
//定义第1位至8为分别代表金币礼包等级、幸运等级、武器的阶、武器的强化等级、护甲的阶、护甲的强化等级、首饰的阶、首饰的强化等级、
unsigned gmoney{}; //金币礼包等级
gmoney = (in_code5 & 0xF000) >> 12; //0x2000
gmoney *= gmoney;
gmoney *= 10000;
std::cout << "你获得的初始金币为:" << gmoney << std::endl;
char gluck{}; //角色幸运等级
gluck = (in_code5 & 0x0F00) >> 8; //0x0500
std::cout << "你的幸运值为:" << (short)gluck << std::endl;
char weapon_lv; //武器的阶
weapon_lv = (in_code5 & 0x00F0) >> 4;
std::cout << "你的武器阶为::" << (short)weapon_lv << std::endl;
char weapon_ev; //武器的强化
weapon_ev = (in_code5 & 0x000F) ;
std::cout << "你的武器阶为::" << (short)weapon_ev << std::endl;
char army_lv{}; //护甲的阶
army_lv = (in_code6 & 0xF000) >> 12;
std::cout << "你的护甲阶为::" << (short)army_lv << std::endl;
char army_ev{}; //护甲的等级
army_ev = (in_code6 & 0x0F00) >> 8;
std::cout << "你的护甲等级为:" << (short)army_ev << std::endl;
char neck_lv{}; //首饰的阶
neck_lv = (in_code6 & 0x00F0) >> 4;
std::cout << "你的首饰阶为:" << (short)neck_lv << std::endl;
char neck_ev{}; //首饰的等级
neck_ev = (in_code6 & 0x000F);
std::cout << "你的首饰等级为:" << (short)neck_ev + 1<< std::endl;
}
else
{
std::cout << "你输入的激活码错误,游戏激活失败!!!\n";
}
}