我必须在一个变量中存储多达7个字节的数据,并且能够读取和写入各个位。有4个字节,这是小菜一碟,我只是使用for循环并执行一次移位来写入该位或读取它:
data : int64;
data := $01 + ($00 shl 8 ) + ($00 shl 16 ) + ($FF shl 24);
for i := 31 downto 0 do
begin
if ((data shr i) and 1) = 1 then ShowMessage('data bit was one')
else ShowMessage('data Bit was Zero');
end;
以正确的顺序读出位。
但是,当我尝试使用此方法超过32位时,似乎已经失败了:
data : int64;
data := $01 + ($00 shl 8 ) + ($00 shl 16 ) + ($00 shl 24) + ($FF shl 32);
for i := 39 downto 0 do
begin
if ((data shr i) and 1) = 1 then ShowMessage('data bit was one')
else ShowMessage('data Bit was Zero');
end;
这不会以正确的顺序输出这些位,$ FF似乎被推到了堆栈的后面。它似乎读取位31到0然后读取位39到32.我如何克服这个问题?
答案 0 :(得分:7)
您的常量被视为Int32值,并且计算使用32位值,并且在所有计算之后都会转换为Int64。
SHL执行为
{Value shl (Shift mod DATASIZE)}
,其中DATASIZE为32,因此对于32位类型,{shl 32}相当于{shl 0}。比较
i64 := Int64($FF) shl 32;
and
i64 := $FF shl 32;
(对于32位编译器,至少)
只需将常量强制转换为Int64以帮助编译器。
答案 1 :(得分:4)
你真的使用Int64表示吗?否则,如果您只是为了这些位,您可以简单地声明一个正确的类型并使用通常的set语法。您也可以使用Include / Exclude设置/重置单个位。
type
T64BitSet = set of 0..63;
var
data: T64BitSet;
begin
data := [0, 32..39]; // set Bits
for i := 39 downto 0 do
begin
if i in data then
<data bit was one>
else
<data Bit was Zero>;
end;
end;
答案 2 :(得分:4)
按位移位运算符的documentation表示(我强调):
操作x shl y和x shr y将x的值向左或向右移位y位,其中(如果x是无符号整数)相当于将x乘以或除以2 ^ y;结果与x的类型相同。例如,如果N存储值01101(十进制13),则N shl 1返回11010(十进制26)。 请注意,y的值以x 类型的大小为基础进行解释。因此,例如,如果x是整数,则x shl 40被解释为x shl 8,因为整数是32位而40 mod 32是8.
这解释了治疗:
$FF shl 32
文字$FF
是32位整数,此表达式与$FF shl 0
相同,即$FF
。
你需要左手操作数为64位类型,这是通过强制转换实现的:
UInt64($FF) shl 32