【问题标题】:Random Numbers from 0 to &HFFFFFFFF从 0 到 &HFFFFFFFF 的随机数
【发布时间】:2013-05-01 18:30:47
【问题描述】:

有什么方法可以在 Visual Basic 6.0 中生成从 0 到 &HFFFFFFFF 的随机数?

我正在使用以下功能

Function RandomNumberLong(Lowerbound As Long, Upperbound As Long) As Long
    RandomNumberLong = Clng((Upperbound - Lowerbound + 1) * Rnd + Lowerbound)
End Function

如果我使用

x = RandomNumberLong(0,&HFFFFFFFF)

它总是返回 0

这里的问题是long可以容纳的最大值是十进制的7FFFFFFF或2147483647 那么我应该如何解决这个问题呢?即使我使用单一数据类型,它也总是返回没有无符号数字的负数。

根据 MSDN 长类型

Long(长整数)变量存储为带符号的 32 位(4 字节) 数值范围从 -2,147,483,648 到 2,147,483,647。 Long 的类型声明字符是和号 (&)。

但是FFFFFFFF的值等于-1或者4294967294溢出了。

我想我对此感到困惑。

已编辑:

由于这似乎有点复杂,我编写了一个小的 Shell 代码来使用 RDTSC 指令来生成一个随机长数,包括有符号和无符号。

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ 
(Destination As Any, Source As Any, ByVal Length As Long)

Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" _ 
(ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long

Option Explicit

 Private Sub Form_Load()
 Dim x(1 To 10) As Byte, VAL As Long

    CopyMemory x(1), &H60, 1 'PUSHAD
    CopyMemory x(2), &H310F, 2 'RDTSC EAX holds a random value

    CopyMemory x(4), &HA3, 1 'MOV EAX
    CopyMemory x(5), VarPtr(VAL), 4 'Pointer of variable // MOV DWORD [VAL],EAX 

    CopyMemory x(9), &H61, 1 'POPAD
    CopyMemory x(10), &HC3, 1 'RET
    CallWindowProc VarPtr(x(1)), 0, 0, 0, 0 'Call the shellcode

    MsgBox VAL
    End Sub

【问题讨论】:

  • 只需使用适当的 PRNG 并读取 4 个字节。
  • 请注意,这种调用机器码的方法不安全!它会在带有data execution protection 的现代 Windows 系统上失败,使其在现代系统上变得脆弱或彻底崩溃。您必须使用VirtualProtect WinAPI 函数预先将此类内存标记为可执行。 Here’s an example code – 尽管是德国 cmets。
  • 是的,差点忘了,谢谢你的提醒。

标签: random vb6


【解决方案1】:

&HFFFFFFFF - 代表32位有符号整数,&HFFFFFFFF的值溢出整数变成-1 因此,当您调用 RandomNumberLong 函数时,您将 0 传递给 Lowerbound,将 -1 传递给 Upperbound

为了在 Vb.NET 中解决此问题,请使用 &HFFFFFFFFL 或 &HFFFFFFFF& 来指示 Long 类型文字。从上面的示例中,我不确定如何在 VB6 中像在 VB.NET 中一样快速地解决这个问题。我猜你需要编写自己的函数来将大的 HEX 数字转换为 double 并传递数字而不是 HEX。

编辑: 我认为 VB6 不允许您将 &HFFFFFFFF 转换为基数 16 以外的任何值,这会溢出并导致 -1:

编辑 2: 您可以通过在末尾添加& 将一些十六进制数字转换为其他数据类型:

&HFFFF = -1
&HFFFF& = 65535

不过,VB6 中的十六进制数似乎有一个限制(仅基数 16?),因为:

VB.NET:
&HFFFFFFFF&=4294967295

VB6:
&HFFFFFFFF&=-1

MSDN: Type Characters (Visual Basic)

编译器通常将整数文字解释为十进制(以 10 为基数)数字系统。您可以使用 &H 前缀将整数文字强制为十六进制(以 16 为基数),并且可以使用 &O 前缀将其强制为八进制(以 8 为基数)。前缀后面的数字必须适合数字系统。

【讨论】:

  • 感谢 George 解决这个问题。我已经使用 RDTSC 指令来生成一个随机长数。你可以在问题中看到它。
【解决方案2】:

事实是 VB6 Long 是 32 位 有符号 整数数据类型。因此它根本无法存储&HFFFFFFFF (MSDN)。但是(1)无论如何,您似乎都可以使用Long,并且(2)您没有解释您的用例是什么,以及仅在正范围内工作是否真的那么重要。

可以使用以下函数从Long 数据类型的整个范围(即从-&H80000000 到&H7FFFFFFF)中生成随机Long 值:

Function RandomNumberLong() As Long
    RandomNumberLong = &H7FFFFFFF * Rnd() + (-1 - &H7FFFFFFF) * Rnd()
End Function

【讨论】:

    【解决方案3】:

    问题在于 VB6 会将仅从“F”中退出的任何十六进制数转换为 -1

    这将使您的函数使用 -1 作为其上限,并使其返回 0

    通过将 8 位数字分成 2 个 4 位变量,您仍然会遇到同样的问题,因为 VB6 仍会将 &HFFFF 转换为 -1,这将使您的函数再次返回 0。

    一种解决方案是在转换之前将&H10000添加到4位变量中,并在转换完成后减去Val("&H10000")。

    之后你可以使用这2个值来获得2个随机数,并将它们组合成1个随机的8位十六进制数。

    下面是一个测试项目,它说明了我的意思:

    '1 form with:
    '  1 command button: name=Command1
    Option Explicit
    
    Private Sub Command1_Click()
      Dim strX As String
      Dim lngX As Long
      strX = RndHex("FFFFFFFF")
      lngX = Val("&H" & strX)
      Caption = strX & " = " & CStr(Hex$(lngX)) & " = " & CStr(lngX)
    End Sub
    
    Function RndHex(strMax As String) As String
      Dim strMax1 As String, strMax2 As String
      Dim lngMax1 As Long, lngMax2 As Long
      Dim lngVal1 As Long, lngVal2 As Long
      Dim strVal1 As String, strVal2 As String
      'make sure max is 8 digits
      strMax1 = Right$("00000000" & strMax, 8)
      'split max in 2 parts
      strMax2 = Right$(strMax1, 4)
      strMax1 = Left$(strMax1, 4)
      'convert max values from string to values
      lngMax1 = Val("&H1" & strMax1) - Val("&H10000")
      lngMax2 = Val("&H1" & strMax2) - Val("&H10000")
      'calculate separate random values
      lngVal1 = CLng(lngMax1 + 1) * Rnd
      lngVal2 = CLng(lngMax2 + 1) * Rnd
      'convert values to 4 digit hex strings
      strVal1 = Right$("0000" & Hex$(lngVal1), 4)
      strVal2 = Right$("0000" & Hex$(lngVal2), 4)
      'combine 2 random values and return the result as an 8 digit hex string
      RndHex = strVal1 & strVal2
    End Function
    
    Private Sub Form_Load()
      'seed random generator with system timer
      Randomize
    End Sub
    

    运行上面的项目,点击命令按钮,查看表单标题中的值。

    【讨论】:

    • “问题是 VB6 将任何仅从“F”退出的十六进制数转换为 -1” - 不完全准确。 &HF=15、&HFF=255、&HFFF=4095、&HFFFF=-1、&HFFFFF=1048575、&HFFFFFF=16777215、&HFFFFFFF=268435455、&HFFFFFFFF=-1以及除此之外的所有内容都会导致编译错误。
    • 此外,&HFFFF&=65535。因此,只有在 &HFFFFFFFF 这样的大 HEX 数字之后,我们才会开始看到溢出。之前的一切看起来都不错。
    • 我同意,我简化了答案。我想我应该说 4 个字节的集合。我没有想到在末尾添加一个 &,因为它不适用于 8 个字节,很好的添加!
    【解决方案4】:

    Rnd 只会给你 24 位随机性,因为它返回一个 Single。

     RandomNumberLong = Clng(&HFFFF * Rnd()) + (Clng(&HFFFF * Rnd()) * &H10000)
    

    将从两个 16 位随机整数构造一个 32 位值。

    更新 - 好吧,它不会,因为正如 Hrqls 指出的那样,&HFFFF 在 VB 中是 -1。而是:

     RandomNumberLong = Clng(65535 * Rnd()) + (Clng(65535 * Rnd()) * 65536)
    

    【讨论】:

    • 似乎没有回答这个问题。现在,他的随机性为 0。 :P 这个错误几乎肯定与Single 的精度无关。 (话虽如此,这仍然是以后的好信息,当这个东西实际上能够产生数字时。)
    • 我测试了你的函数,它返回以下 FFFEFFFF 或 FFFF0000 或 FFFFFFFF 或 0 之一。
    • Single 在 VB6 中是 32 位的。
    • 是的,Single 是 32 位,但是 Rnd 返回一个介于 0 和 1 之间的值,因此符号位和 7 个指数位不会增加任何随机性。
    • +1 用于将 8 位数字拆分为 2x 4 位数字……尽管 vb 仍将 &HFFFF 转换为 -1,但问题仍然存在……请参阅下面的答案,该答案可以解决该问题
    猜你喜欢
    • 2017-05-28
    • 2013-11-21
    • 1970-01-01
    • 2014-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多