本話題涉及: 1、常用二進制的位操作; 2、集合與 "位" 的關系; 3、TBits 類.
這裡的 "位" 是指二進制位, 譬如一個 Byte 有 8 個位、一個 Integer 有 32 個位.
在 C 語言中可以定義由 "位" 字段構成的結構體, 但因效率問題好像使用也不廣泛.
假如要保存八種狀態(True/False), 最笨的辦法可以使用下面的結構體:
type
TState = record
b1, b2, b3, b4, b5, b6, b7, b8: Boolean;
end;
其實用 1 個字節就可以表示 8 種狀態了, 因為 1 個字節就有 8 個位.
這裡是假定用每個位表示一個狀態, 如果要算上各種組合這一個字節能表示 255 種情形.
系統函數中的很多 "選項" 就是基於 "位".
先來幾個簡單的關於 "位" 的練習:
{這是查看二進制的函數}
function ToBin(p: PByteArray; b: Integer): string;
var
i,j: Integer;
begin
Result := StringOfChar('0' , b * 8);
for i := 0 to b - 1 do for j := 0 to 7 do
if Odd(p^[b-1-i] shr j) then Result[i*8 + 8 - j] := '1';
end;
{把一個二進制數賦給一個變量的方法}
procedure TForm1.Button1Click(Sender: TObject);
var
b1,b2,b3: Byte;
begin
{雖 Delphi 常規下不支持二進制常量, 但其內嵌匯編支持}
asm
mov b1, 11100110B
end;
b2 := 230;
b3 := $E6;
{現在是給 b1 b2 b3 賦了同樣的值}
ShowMessageFmt('%d, %d, %d', [b1, b2, b3]); //230, 230, 230
end;
{使用 or 確保第二、三位是 1}
procedure TForm1.Button2Click(Sender: TObject);
var
b1, b2: Byte;
begin
asm
mov b1, 11100010B
mov b2, 00000110B
end;
b1 := b1 or b2;
ShowMessage(ToBin(@b1, 1)); {11100110}
end;
{使用 and 確保第二、三之外的位是 0}
procedure TForm1.Button3Click(Sender: TObject);
var
b1, b2: Byte;
begin
asm
mov b1, 11100010B
mov b2, 00000110B
end;
b1 := b1 and b2;
ShowMessage(ToBin(@b1, 1)); {00000010}
end;
{使用 and 探測第二、三位是否是 1}
procedure TForm1.Button4Click(Sender: TObject);
var
b: Byte;
begin
asm mov b, 11100010B end;
if 2 and b = 2 then ShowMessage('第二位是 1');
{上面可以理解為: if 00000010B and b = 00000010B then ...}
if 4 and b = 4 then ShowMessage('第三位是 1');
{上面可以理解為: if 00000100B and b = 00000100B then ...}
end;
{使用 shr 探測第二、三位是否是 1}
procedure TForm1.Button5Click(Sender: TObject);
var
b: Byte;
begin
asm mov b, 11100010B end;
if Odd(b shr 1) then ShowMessage('第二位是 1');
if Odd(b shr 2) then ShowMessage('第三位是 1');
end;
用一個 Byte 值保存八種狀態的實例:
准備工作:
1、在空白窗體上添加 CheckListBox1;
2、添加四個 Button, 並激活 Button1 的 OnClick 事件; 3、激活窗體的 OnCreate 事件.
var b: Byte; {用它記錄八個 CheckBox 的選擇狀態}
procedure TForm1.FormCreate(Sender: TObject);
begin
CheckListBox1.Items.CommaText := 'A,B,C,D,E,F,G,H';
Button1.Caption := '保存狀態';
Button2.Caption := '恢復狀態';
Button3.Caption := '全選';
Button4.Caption := '全不選';
Button1.Tag := 1;
Button2.Tag := 2;
Button3.Tag := 3;
Button4.Tag := 4;
Button2.OnClick := Button1.OnClick;
Button3.OnClick := Button1.OnClick;
Button4.OnClick := Button1.OnClick;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
if TButton(Sender).Tag = 1 then b := 0;
for i := 0 to CheckListBox1.Count - 1 do
case TButton(Sender).Tag of
1: if CheckListBox1.Checked[i] then b := b or (1 shl i);
2: CheckListBox1.Checked[i] := Odd(b shr i);
3: CheckListBox1.Checked[i] := True;
4: CheckListBox1.Checked[i] := False;
end;
end;
測試效果圖("恢復" 寫成 "回復" 了):
"位" 操作有點抽象, 用 "集合" 代替上面的操作就簡明多了; 接下來討論 "集合" 的本質.