C ++与C#计算(错误结果)

问题描述 投票:-4回答:2

我有一点问题;

我有这个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(错误)

我希望有人可以解释一下。

c# c++ math
2个回答
2
投票

因此,这里有三个(至少)潜在问题。

  1. 该算法呈指数级增长,不提供任何保护。它很容易逆转,不会尝试确保输入。
  2. pow(pass, 3.0)方法将返回double
  3. long数据类型(在C ++中)并不总是64位。它可以是32位。

如果我们忽略第一点,并跳到第二点,则有两个潜在的问题:

  1. pow(pass, 3.0)线被击中时,由于浮点错误,它可能并不总是返回相同的值。 (现在,我不怀疑这是您的代码中的一个主要问题,但您没有考虑到它。)
  2. 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位的。

如果你需要一个串口或哈希(我们在现实世界中称它们),我建议你看看md5sha1/2或任何其他哈希算法。 (这里提到的所有三个都内置在.NET中,应该很容易将它们用于C ++。)

如何判断我的C ++环境是否支持64位unsigned long变量?

容易,用unsigned longunsigned int)的最大值播种4,294,967,295值,加一个,并检查该值是否小于1。

unsigned long test = 4294967295;
test = test + 1;
bool longIs64Bits = test > 0;

结果应该是truefalse。如果true,那么你有一个64位unsigned long类型。如果false,那么你没有。

如果我真的需要64位数字怎么办?

幸运的是,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规范的一部分,但我无法保证对它的支持。


0
投票

EBrown是正确的,C ++代码需要认真重新思考,但如果C ++代码是遗留的并且您无法更改它,那么您可以做的最好是复制C#版本中的错误。

在c#版本中使用uint而不是long来触发无符号32位溢出。

您无法可靠地复制双舍入错误。使用Math.pow并祈祷它永远不会出现。

编辑:附录:朋友们不要让朋友们自己加密。

© www.soinside.com 2019 - 2024. All rights reserved.