正如 David 在此处的答案评论中所问的那样,我对这个函数的工作原理非常感兴趣,因为如果将结果长度从 32 更改为 16 或 8,我似乎无法获得相同(正确)的值。
我用了函数
function IntToBin(Value: LongWord): string;
var
i: Integer;
begin
SetLength(Result, 32);
for i := 1 to 32 do begin
if ((Value shl (i-1)) shr 31) = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
这在某种程度上工作得很好。(1 返回为 000...001,2 返回为 000...010,3 返回为 000...011,等等...)。
但是,由于我只需要 8 个字符长的字符串结果,因此我将函数中的数字更改为 8 以获得以下结果:
function IntToBin(Value: LongWord): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 1 to 8 do begin
if ((Value shl (i-1)) shr 7) = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
但我得到的结果如下:
1: 00000001
2: 00000011
3: 00000011
4: 00000111
5: 00000111
6: 00000111
7: 00000111
8: 00001111
9: 00001111
10: 00001111
11: 00001111
12: 00001111
Run Code Online (Sandbox Code Playgroud)
16 个而不是 8 个有点相同。
也尝试将 LongWord 更改为 Integer 和 Byte,但得到了相同的结果。
那么...嗯...我在这里想念什么,不明白吗?:/
PS:出于学习目的询问,在第一个函数末尾用 Copy(Result, 25, 8) 解决了我的情况,因为需要传递 8 个字符长的字符串,但我真的想了解发生了什么......:)
谢谢
代码中的左移意味着将您感兴趣的位移动到数据类型的最左边缘。通过这样做,左侧的所有位都会从末尾移出并丢失。然后当你再次向右移动时,我们就一直移动到另一端。结果要么是 0,要么是 1。
然而,您的数据类型仍然是 32 位,因此您移动的距离还不够远。您不会让目标位左侧的所有位都从末尾脱落。因此,当您向右移动时,它们会返回。
为了让你的代码工作,你需要这个:
function IntToBinLowByte(Value: LongWord): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 1 to 8 do begin
if ((Value shl (24+i-1)) shr 31) = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
相对于原始版本,可能更容易理解的版本如下:
function IntToBinLowByte(Value: LongWord): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 25 to 32 do begin
if ((Value shl (i-1)) shr 31) = 0 then begin
Result[i-24] := '0'
end else begin
Result[i-24] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
但坦率地说,最好对单个字节进行操作。我发现这种双重转变有点晦涩难懂。我会使用一个移位和一个位掩码。像这样:
function IntToBinByte(Value: Byte): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 1 to 8 do begin
if (Value shr (8-i)) and 1 = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
并这样称呼它
str := IntToBinByte(Value and $ff);
Run Code Online (Sandbox Code Playgroud)
假设Value是 32 位数据类型。显然,如果它已经是 aByte那么你不需要按位and。
在我看来,原来的 32 位函数会像这样读起来更好。
此答案的早期版本有以下错误尝试来解决问题:
function IntToBinByte(Value: Byte): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 1 to 8 do begin
if ((Value shl (i-1)) shr 7) = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
问题是,尽管Value是8位类型,但按位运算是在32位寄存器中执行的。因此,当执行右移时,左移到位数 >7 的位将返回。您可以通过屏蔽掉那些应该从末端掉落的部分来轻松解决此问题。像这样:
function IntToBinByte(Value: Byte): string;
var
i: Integer;
begin
SetLength(Result, 8);
for i := 1 to 8 do begin
if (Value shl (i-1) and $ff) shr 7 = 0 then begin
Result[i] := '0'
end else begin
Result[i] := '1';
end;
end;
end;
Run Code Online (Sandbox Code Playgroud)
这段代码确实很复杂,我不建议任何人使用它。在我看来,最好的版本是我答案中的第三个代码块。