前言
本文說明 C 語言中與布林相關的常見議題,以及在不同語言標準與開發環境下的處理方式,並展示一個具有良好可攜性的布林型態實作。
常見情境
C89
早期的 C(例如 C89)並沒有正式定義布林型態。不過,C 語言本身具有一個簡單的「布林語境」(boolean context)。
在這個語境中:
00.0'\0'(字串結尾)NULL
會被視為 偽(false),而任何 非零值 則會被視為 真(true)。
如果需要顯式的布林型態,可以使用類似以下的做法:
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
不過,在 C99 之後語言已正式引入布林型態,因此在現代專案中不建議直接加入這組 macro。
C99 及其之後
從 C99 開始,標準函式庫 stdbool.h 明確定義了:
- 布林型態:
bool - 真值:
true - 偽值:
false
程式設計者只需要:
#include <stdbool.h>
即可使用標準布林型態,而不需要自行宣告。
C++
C++ 本身也內建布林型態:
booltruefalse
在實務開發中,C 與 C++ 程式碼混合使用並不罕見,因此設計可攜的布林型態時通常需要考慮這個情境。
Objective-C
由於歷史原因,Objective-C 並沒有沿用 C99 的 stdbool.h,而是使用自己的布林定義:
BOOLYESNO
無論是 Cocoa 或 GNUstep,通常都建議將 Objective-C Runtime 視為一個相對獨立的運行環境,避免在 Objective-C 程式中混入過多純 C 的自訂型態。
不需要定義布林的情境
在許多情況下,C 程式其實不需要明確定義布林型態。
原因是 C 語言的條件判斷本來就建立在「零與非零」的概念上:
0或NULL→ 偽(false)- 非零值或非
NULL→ 真(true)
這個行為在所有 C 標準中都是一致的。
以下是一段示意程式碼:
list_t *lt = list_new();
if (!lt) {
goto PROGRAM_ERROR;
}
/* Run some code here. */
list_delete((void *) lt);
return EXIT_SUCCESS;
PROGRAM_ERROR:
if (lt) {
list_delete((void *) lt);
}
return EXIT_FAILURE;
在這段程式中,如果 list_new() 初始化失敗並回傳 NULL,程式就會跳到 PROGRAM_ERROR 標籤處理錯誤流程,最後回傳 EXIT_FAILURE。
整個流程中並沒有使用顯式的布林型態,但程式依然能清楚地表達邏輯,因此在這類情境下 定義布林型態並不是必要條件。
為什麼不直接使用 stdbool.h?
在大多數現代 C 專案中,直接使用 stdbool.h 是最簡單且標準的做法。
然而,在某些情況下仍可能需要自訂布林型態,例如:
- 專案需要支援 C89 或更舊的編譯器
- 程式碼需要在 C 與 C++ 之間共享
- 希望維持與 既有 API(例如 Win32 的
BOOL) 一致的命名風格 - 函式庫希望提供 自包含(self-contained)的型態定義
在這些情境下,提供一個可攜的布林型態標頭檔,能讓程式碼在不同平台與語言標準下保持一致。
跨平台布林宣告
由於不同 C 版本對布林的支援程度不同,綜合上述情境,我們可以設計一個具有良好可攜性的布林標頭檔:
/** @file boolean.h
* @brief Custom Boolean type for C (portable & self-contained)
* @author ByteBard
* @copyright MIT
*
* Note: Win32 API provides its own BOOL type. This header is not intended for use in Win32 API programming.
*/
#ifndef CLIBS_BOOLEAN_H
#define CLIBS_BOOLEAN_H
#if defined(_WIN32)
/* On Windows, use the native Win32 BOOL */
#include <windows.h>
#else /* Not Windows */
#ifndef CLIBS_BOOL_DEFINED
#if defined(__cplusplus)
typedef bool BOOL;
#define TRUE true
#define FALSE false
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#include <stdbool.h>
typedef bool BOOL;
#define TRUE true
#define FALSE false
#else
typedef unsigned char BOOL;
#define TRUE 1
#define FALSE 0
#endif
#define CLIBS_BOOL_DEFINED
#endif /* CLIBS_BOOL_DEFINED */
#endif /* _WIN32 */
#endif /* CLIBS_BOOLEAN_H */
這個實作考慮了以下幾種情境:
- Windows 平台(直接使用 Win32 的
BOOL) - C++
- C99 以上版本
- 舊版 C(例如 C89)
藉由條件編譯,可以讓同一份程式碼在不同平台與編譯器下都能正常運作。
Objective-C 的情境
Objective-C 通常會將 Foundation 視為預設環境,因此自訂布林型態的需求較低。
在這種情況下,本標頭檔通常會顯得多餘,因此本文不特別針對 Objective-C 進行處理。
另見
本標頭檔出自於專案:clibs
If you need a minimal portable boolean implementation for C projects,
you can directly include the header from the clibs repository.