我有一点问题;
我有这个C ++计算:
int main(unsigned long pass){
char name[50];
cout << "Enter username please: " << endl << endl;
gets_s(name);
cout << "\n";
pass = strlen(name);
pass = pass * 3;
pass = pass << 2;
pass = pow(pass, 3.0);
pass = pass + 23;
pass = pass + (pass * 708224);
cout << "Your generated serial: " << +pass << endl << endl;
system("pause");}
这为我提供了3个字符用户名的工作代码。
这是我的C#计算。
private void btn_generate_Click(object sender, EventArgs e)
{
pass = txt_user.TextLength;
pass = pass * 3;
pass = pass << 2;
pass = pass * pass * pass;
pass = pass + 23;
pass = pass + (pass * 708224);
txt_serial.Text = pass.ToString();
}
这给了我完全相同用户名的错误代码..
奇怪的是,两者的计算给出了相同的结果,直到这一行:
pass = pass + (pass * 708224);
在此计算之后,C#给出了错误的结果。
c ++结果:2994463703
(正确)
c#results:33059234775
(错误)
我希望有人可以解释一下。
答案 0 :(得分:2)
所以,这里有三个(至少)潜在问题。
pow(pass, 3.0)
方法 以返回double
。long
数据类型(在C ++中)并不总是 64位。它可以 32位。如果我们忽略第一点,并跳到第二点,则有两个潜在的问题:
pow(pass, 3.0)
行被点击时,由于浮点错误,可能并不总是返回相同的值。 (现在,我不怀疑这是您的代码中的一个主要问题,但您没有考虑到它。)pass + (pass * 708224)
行(可以重写为pass * 708225
fyi)被命中时,在32位C ++环境中,它将静默溢出到值{{ 1}},恰好是您的C ++结果。那么,你如何解决这个问题?
修复该算法。就目前而言,您可以轻松构建潜在值的查找表。
2,994,463,703
现在,问题不在于这些数字总是将是相同的,这通常是预期的。问题是实际适合Input (pass) Output
1 1,240,154,505
2 9,806,791,575
3 33,059,234,775
4 78,340,308,375
5 152,992,889,175
etc. etc.
的唯一值是第一个。一旦计算出第二个字符,它就会超出潜在范围。如果您要在C ++中执行此操作,则应该尽量避免使用Int32
数据类型。它们并不总是保证是64位。
如果您需要序列或哈希(正如我们在现实世界中所称),我建议您查看long
,{{1或任何其他哈希算法。 (这里提到的所有三个都内置在.NET中,应该很容易将它们用于C ++。)
md5
变量?很简单,使用sha1/2
(unsigned long
)的最大值为unsigned long
种子,添加一个值,然后检查该值是否小于1.
unsigned int
结果应为4,294,967,295
或unsigned long test = 4294967295;
test = test + 1;
bool longIs64Bits = test > 0;
。如果是true
,则您拥有64位false
类型。如果true
,那么你不会。
幸运的是,C ++还提供了unsigned long
变量类型。 (以及false
。)注意:这些数据类型的大小可能会有所不同,但不小于 64位。
long long
前面的代码段应始终为真。
最后,unsigned long long
中还定义了unsigned long long test = 4294967295;
test = test + 1;
bool longLongIs64Bits = test > 0;
。这保证是64位。它是C99规范和C ++ 11规范的一部分,但我无法保证支持它。
答案 1 :(得分:0)
EBrown是正确的,C ++代码需要认真重新思考,但如果C ++代码是遗留的而你无法改变它,那么你能做的最好就是复制C#版本中的bug。
在c#版本中使用uint
而不是long
来触发无符号32位溢出。
您无法可靠地复制双舍入错误。使用Math.pow
并祈祷它永远不会出现。
编辑: 附录:朋友不要让朋友们自己加密。