HOWTO · C

如何在 C 語言中比較位元

本文示範如何在 C 語言中比較位元。

本頁內容

按位元運算是電腦程式設計的基礎,尤其是在處理低階資料操作時。在 C 語言中,有幾種比較單個位元或位元群組的方法。

在本文中,我們將探討不同的技術,並附上程式碼範例來示範每種方法。

在 C 語言中使用按位元 XOR 和 AND 運算實現按位元比較的自訂函式

按位元 AND 運算子(&)用於對兩個運算元的對應位元執行按位元比較。此運算產生一個新值,其中每個位元僅當兩個運算元中的對應位元都被設定時才被設定。

範例程式碼:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 & num2;

  printf("Result: %u\n", result);  // Output: 0 (Binary: 0000)

  return 0;
}

輸出:

Result: 0

在此範例中,num1 和 num2 分別用值 9 和 6 初始化。這些值以二進位表示為 1001 和 0110。

num1 和 num2 之間的按位元 AND 運算(num1 & num2)結果以二進位表示為 0000,以十進位表示為 0。這意味著 num1 和 num2 中沒有同時被設定的對應位元。

同時,按位元 XOR 運算子(^)用於對兩個運算元的對應位元執行按位元比較。此運算產生一個新值,其中每個位元在運算元中的對應位元不同時被設定。

範例程式碼:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 ^ num2;

  printf("Result: %u\n", result);  // Output: 9 (Binary: 1001)

  return 0;
}

輸出:

Result: 15

在此範例中,按位元 XOR 運算(num1 ^ num2)結果以二進位表示為 1001,以十進位表示為 9。這意味著 num1 和 num2 中的對應位元不同。

通常,位元比較需要存取單個位元值並進行所需的操作,例如使用 union 和 struct 關鍵字實現位元欄位。

但是,按位元運算提供了一種比較數字中指定位元的更有效方法。在這種情況下,我們將實現一個適用於 u_int32_t 型別的單獨函式,該型別保證具有 32 位元寬度。

下面的範例程式將三個整數用作命令列引數,其中前兩個是要比較的數字,而第三個整數指定第 n 位元。注意,我們使用 strtol 轉換 argv 元素,因此在以 u_int32_t 型別儲存回傳值時會損失一些精度。

compareBits 函式宣告兩個儲存中間值的區域變數 - mask 和 tmp。我們透過將 1 向左移動 nth - 1 個位置來設定 mask 中的第 n 個位元。

然後,對兩個使用者輸入數字進行 XOR 運算,以得到每個位置的位元差,並在結果中以設定的位元表示不同的值。最後,我們需要從第 n 個位置提取該位元,並檢查該值是否為 0。

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool compareBits(u_int32_t n1, u_int32_t n2, u_int32_t nth) {
  u_int32_t mask, tmp;

  mask = 1 << (nth - 1);
  tmp = n1 ^ n2;

  if ((tmp & mask) == 0)
    return true;
  else
    return false;
}

int main(int argc, char *argv[]) {
  u_int32_t num1, num2, bit;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s integer1 integer2 nth_bit \n", argv[0]);
    exit(EXIT_FAILURE);
  }

  num1 = strtol(argv[1], NULL, 0);
  num2 = strtol(argv[2], NULL, 0);
  bit = strtol(argv[3], NULL, 0);

  compareBits(num1, num2, bit) ? printf("bits equal!\n")
                               : printf("bits not equal!\n");

  exit(EXIT_SUCCESS);
}

範例檔案格式:

./main 1234 1231 1

輸入檔案格式:

bits not equal!

例如,整數 1234 和 1231 以二進位分別表示為 00000000000000000000010011010010 和 00000000000000000000010011001111。

因此,對這兩個數進行 XOR 運算得到二進位表示 00000000000000000000000000011101,最終將其與遮罩 00000000000000000000000000000010 進行 AND 運算,以提取單個位元位置的值。如果結果全為零,則意味著比較的位元相等;否則,恰恰相反。

不過,或者,我們可以縮短 compareBits 函式,並將 XOR/AND 運算移動到 return 陳述式中,如以下範例程式碼所示。注意,該函式回傳按位元 XOR/AND 運算的邏輯相反值,因為我們在呼叫方函式中使用 ? : 三元陳述式輸出相應的訊息。

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

bool compareBits(u_int32_t n1, u_int32_t n2, u_int32_t nth) {
  u_int32_t mask;

  mask = 1 << (nth - 1);

  return !((n1 ^ n2) & mask);
}

int main(int argc, char *argv[]) {
  u_int32_t num1, num2, bit;

  if (argc != 4) {
    fprintf(stderr, "Usage: %s integer1 integer2 nth_bit \n", argv[0]);
    exit(EXIT_FAILURE);
  }

  num1 = strtol(argv[1], NULL, 0);
  num2 = strtol(argv[2], NULL, 0);
  bit = strtol(argv[3], NULL, 0);

  compareBits(num1, num2, bit) ? printf("bits equal!\n")
                               : printf("bits not equal!\n");

  exit(EXIT_SUCCESS);
}

範例檔案格式:

./main 1234 1231 2

輸入檔案格式:

bits equal!

在 C 語言中使用按位元 OR(|)運算子進行位元比較

按位元 OR 運算子(|)對兩個運算元的對應位元執行按位元比較。此運算的結果是一個新值,其中每個位元在任一運算元中的對應位元至少有一個被設定時被設定。

當應用於一對位元時,OR 運算遵循以下邏輯:

`0 0`
`0 1`
`1 0`
`1 1`

請看以下範例來說明按位元 OR 運算:

#include <stdio.h>

int main() {
  unsigned int num1 = 9;  // Binary representation: 1001
  unsigned int num2 = 6;  // Binary representation: 0110

  unsigned int result = num1 | num2;

  printf("Result: %u\n", result);  // Output: 15 (Binary: 1111)

  return 0;
}

輸出:

Result: 15

在此範例中,我們有兩個無號整數 num1 和 num2,分別用值 9 和 6 初始化。它們的二進位表示為 1001 和 0110。

當我們執行按位元 OR 運算(num1 | num2)時,結果以二進位表示為 1111,以十進位表示為 15。這意味著 num1 或 num2 中至少有一個對應位元被設定。

在 C 語言中使用按位元 NOT(~)運算子進行位元比較

按位元 NOT 運算子(~)是一元運算子,意味著它對單個運算元進行運算。當應用於二進位數時,它會反轉每個位元,將 0 變為 1,將 1 變為 0。

範例程式碼:

#include <stdio.h>

int main() {
  unsigned int num = 9;  // Binary representation: 1001

  unsigned int result = ~num;

  printf(
      "Result: %u\n",
      result);  // Output: 4294967286 (Binary: 11111111111111111111111111111010)

  return 0;
}

輸出:

Result: 4294967286

在此範例中,我們宣告一個無號整數變數 num 並用值 9 初始化它。以二進位表示為 1001。

然後我們應用按位元 NOT 運算子(~num)。這會反轉所有位元,得到二進位 11111111111111111111111111111010。

結果被列印到主控台,以十進位表示為 4294967286。

用於比較位元的按位元 NOT

按位元 NOT 運算子的應用之一是比較位元。透過反轉變數的位元,我們可以輕鬆檢查某個特定位元是被設定還是未被設定。

範例程式碼:

#include <stdio.h>

int main() {
  unsigned int num = 9;  // Binary representation: 1001

  // Check if the 2nd bit is set
  unsigned int mask = 1 << 1;  // Shift 1 by 1 position to the left => 0002

  unsigned int result = ~num & mask;

  if (result == mask) {
    printf("2nd bit is set.\n");
  } else {
    printf("2nd bit is not set.\n");
  }

  return 0;
}

輸出:

2nd bit is set.

在此範例中,我們想檢查變數 num 的第 2 個位元是否被設定。

我們首先透過將 1 向左移動 1 個位置(1 << 1)來建立一個遮罩,得到二進位 0002。然後我們將按位元 NOT 運算子應用於 num,得到二進位 11111111111111111111111111111010。

接下來,我們在反轉後的 num 和遮罩之間執行按位元 AND 運算。這會隔離第 2 個位元。

如果結果等於遮罩,則意味著第 2 個位元被設定,我們列印相應的訊息。否則,我們列印一條訊息,表明第 2 個位元未被設定。

結論

在這次對 C 語言按位元運算子的全面探討中,我們涵蓋了 AND、OR 和 NOT 等基本運算。這些運算對於涉及低階資料操作的任務(例如資料壓縮、加密和嵌入式系統程式設計)非常寶貴。

具體來說,我們深入探討了使用按位元 NOT(~)運算子來比較單個位元。透過應用 ~ 運算子,我們可以輕鬆反轉變數的位元,從而能夠檢查某個特定位元是被設定還是未被設定。這項技術在需要精確位元級操作的場景中至關重要。

理解和掌握按位元運算對於從事涉及與硬體直接互動的任務或需要針對資源受限環境提供最佳化解決方案的程式設計師至關重要。憑藉從本文中獲得的知識,您現在能夠在自己的 C 程式設計專案中利用這些強大的工具。