微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我无法将SHL向左移动与int64变量一起使用

如何解决我无法将SHL向左移动与int64变量一起使用

|
 Result:= b8;
 Result:= Result+ (b7  SHL  8);
 Result:= Result+ (b6  SHL 16);
 Result:= Result+ (b5  SHL 24);
 Result:= Result+ (b4  SHL 32);
 Result:= Result+ (b3  SHL 40);      <------ here
 Result:= Result+ (b2  SHL 48);
 Result:= Result+ (MSB SHL 56);
(结果是int64,b1-b8是字节)。 但是编译器抱怨“常量exp违反了子范围边界”。 然后,我在网站上发现以下警告:“除非数据类型为Int64,否则编译器将拒绝超过32的硬编码移位右值。对于Shl \而言,情况并非如此”。 Delphi Help对此一无所获。为什么有限制?我可以阻止它吗?也许是编译器指令之类的?我可以使用乘法来克服它,但是会慢一些。有更快的方法吗? 编辑: 我也在考虑创建两个基数,因为我可以在基数上使用SHL,然后将基数合并在一起。这将只需要一个乘法。还有其他想法吗? 编辑2: 该代码是算法的一部分,该算法将数字从255转换为256(以相反的方式)。我做了500亿次;所以速度很重要。     

解决方法

我会避免所有算术运算(您的代码具有加法运算和移位运算),并这样做:
Int64Rec(Result).Bytes[0] := b8;
Int64Rec(Result).Bytes[1] := b7;
//etc.
Int64Rec
在SysUtils中定义如下:
Int64Rec = packed record
  case Integer of
    0: (Lo,Hi: Cardinal);
    1: (Cardinals: array [0..1] of Cardinal);
    2: (Words: array [0..3] of Word);
    3: (Bytes: array [0..7] of Byte);
end;
如果将字节存储在数组中,则可以将其全部包裹为“ 4”循环。     ,我假设您的
Result
已经是
Int64
,并且
b8
b7
等被声明为
Byte
。编译器需要一点帮助。键入to6ѭ:
  Result := b8;
  Result := Result + (b7 shl  8);
  Result := Result + (b6 shl 16);
  Result := Result + (b5 shl 24);
  Result := Result + (Int64(b4) shl 32);
  Result := Result + (Int64(b3) shl 40);
  Result := Result + (Int64(b2) shl 48);
  Result := Result + (Int64(msb) shl 56);
    ,这是使用班次的另一种解决方案,但我相信它是“更干净的”(尽管不如David的建议那么干净):
result := MSB;
result := (result shl 8) or b2;  { could use \"shl sizeof(b2)\" instead of 8 }
result := (result shl 8) or b3;
etc
result := (result shl 8) or b8;
此解决方案避免了所有“魔术”移位值,并且可能更易于理解。同样,如果MSB..b8(或b1..b8)是字节数组,则上述代码可以轻松转换为单行循环。 要回答有关为什么编译器不接受值40及更高值的问题,原因很可能是由于SHLD指令的《英特尔指令集参考》第2B卷中的此引号引起的:   在非64位模式和默认64位模式下   模式;仅0至4的位   计数。这掩盖了计数   到0到31之间的值。如果a   计数大于操作数   大小,结果不确定。 SHL指令上的等效条件并不那么严格:   8086不会掩盖这一转变   计数。但是,所有其他IA-32   处理器(从英特尔开始   286处理器)掩盖移位计数   到5位,导致最大值   计数为31。此掩蔽是在   所有操作模式(包括   virtual-8086模式)以减少   的最大执行时间   说明。 在这两种情况下,大于31的值都是无用的(使用SHL时)或未定义的(使用SHLD时)。编译器显然知道这一点,并且它阻止了您编写潜在错误的代码(在64位模式下)。 如果您确实要执行此操作500亿次,那么您可能要考虑以内联汇编的方式进行操作,这将非常简单:
asm
    xor eax,eax   
    or  eax,MSB   { or b1 depending on how you named the MSB }
    shl eax,8
    or  eax,b2
    shl eax,b3
    shl eax,b4
    mov High32bit,eax
end;
对低32位dword和b5至b8重复上述操作。我不建议使用SHLD,因为我不相信Delphi支持64位寄存器或64位指令(我可能是错的,我从未尝试过。) 注意:我听说有传言称64位版本的Delphi将不支持内联汇编。可能会,也可能不是,但除非真正绝对必要,否则我将避免进行内联汇编。 希望能有所帮助, 约翰。 PS:还有另一个原因使David Heffernan的解决方案是最好的解决方案。在我介绍的解决方案中,每条指令都取决于上一条指令(也就是说,必须在执行下一条“或”指令之前将eax移位8)。 David的解决方案设置单个字节,因此,每个分配都独立于先前的分配,这将允许处理器潜在地并行执行多个分配。在这个多核处理器时代,它的潜力可能比我作为示例给出的汇编代码快很多。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。