我有一点问题;
我有这个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 char用户名的工作代码。
这是我的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#结果:33059234775
(错误)
我希望有人可以解释一下。
因此,这里有三个(至少)潜在问题。
pow(pass, 3.0)
方法将返回double
。long
数据类型(在C ++中)并不总是64位。它可以是32位。如果我们忽略第一点,并跳到第二点,则有两个潜在的问题:
pow(pass, 3.0)
线被击中时,由于浮点错误,它可能并不总是返回相同的值。 (现在,我不怀疑这是您的代码中的一个主要问题,但您没有考虑到它。)pass + (pass * 708224)
行(可以重写为pass * 708225
fyi)被击中时,在32位C ++环境中它会静默地溢出到值2,994,463,703
,这恰好是你的C ++结果。那么,你如何解决这个问题呢?
修复该算法。就目前而言,您可以轻松构建潜在值的查找表。
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.
现在,问题不在于这些数字总是一致的,这通常是预期的。问题是,实际上适合Int32
的唯一值是第一个。一旦计算出第二个字符,它就会超出潜在范围。如果您要在C ++中执行此操作,您应该尝试确保避免使用long
数据类型。它们并不总是保证是64位的。
如果你需要一个串口或哈希(我们在现实世界中称它们),我建议你看看md5
,sha1/2
或任何其他哈希算法。 (这里提到的所有三个都内置在.NET中,应该很容易将它们用于C ++。)
unsigned long
变量?容易,用unsigned long
(unsigned int
)的最大值播种4,294,967,295
值,加一个,并检查该值是否小于1。
unsigned long test = 4294967295;
test = test + 1;
bool longIs64Bits = test > 0;
结果应该是true
或false
。如果true
,那么你有一个64位unsigned long
类型。如果false
,那么你没有。
幸运的是,C ++还提供了long long
变量类型。 (以及unsigned long long
。)注意:这些数据类型的大小可能会有所不同,但不会低于64位。
unsigned long long test = 4294967295;
test = test + 1;
bool longLongIs64Bits = test > 0;
前面的代码段应该始终为true。
最后,还有uint64_t
,定义在<stdint.h>
。这保证是64位。它是C99规范和C ++ 11规范的一部分,但我无法保证对它的支持。
EBrown是正确的,C ++代码需要认真重新思考,但如果C ++代码是遗留的并且您无法更改它,那么您可以做的最好是复制C#版本中的错误。
在c#版本中使用uint
而不是long
来触发无符号32位溢出。
您无法可靠地复制双舍入错误。使用Math.pow
并祈祷它永远不会出现。
编辑:附录:朋友们不要让朋友们自己加密。