本文摘錄自 CONTRIBUTING.md :
不要濫用「重點」一詞,原文沒幾行,你只是「摘錄」。
已修正。
/* */
或 //
size_t
ssize_t
uint8_t
,應該使用 unsigned
,除非有資源限制bool
,其他類別要轉換成 bool
應使用比較方式達成,而非強轉型signed int
,不應該在其中宣告 bit-field,以及對其進行 bitwise 操作,後者行為是實作定義的善用 C99 陣列初始化,如:
do-while(0)
包裝return
UINTXX_C
或 INTXX_C
包起來,請考量該常數的應用場景決定是否是 signed
const
),在數字後添加 U
使其被視為 unsigned
看不懂,如果常數是負數為何要加上
U
?
C11 規格書 §6.3.1.8 中提到 signed
和 unsigned
整數的運算轉換規則:
char
、short
等較小的類別轉換 int
或者是 unsigned int
sign
相同時,會轉型成兩者中較高階者 (greater integer conversion rank)sign
不同時,做以下判斷:
unsigned
階級 signed
階級: 使用 unsigned
的類型signed
可表達 unsigned
所有值: 轉換成 signed
的類型unsigned
所屬類型整數提升定義參考 §6.3.1.1-2
If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions58.) All other types are unchanged by the integer promotions.
if
,因為 uint16_t
和 int16_t
會先被轉型成 int
,左側相加會是 int
類型,再後面的 4
(int
) 進行比較,兩者型別一致,且都是 signed
,所以結果符合預期unsigned int
(uint16_t
),因此 -9
透過二補數轉換變 -9 + 2^16
。後續是 uint16_t
和 int
(int16_t
)不同類型的比較,根據 §6.5.9 節,會發生符合 §6.3.1.8 定義的轉型規則,最終的數值類型為 uint16_t
,結果不進入 if
迴圈new
:static
和 constant
,前者尤其可應用在模組內私有函式,後者則可應用在:
#define
作為數值常數const type *p
修飾printf
formatter 應使用如 PRIu64
等格式,而非 %ull
NULL
顯式初始化,以避免解引用未初始化指標造成未定義行為typedef
為指標取別名
是為避免太多指標名稱造成混亂?
const
*
和變數間要有空白restrict
,則 *
和變數間要有空白*
緊鄰變數clang-format 似無法做這種客製化? 嘗試目前 lab0-c 的規則不符合上述情況,會變成:
typedef
為結構體命名別名時,別名應以 _t
結尾.c
檔案中提供 定義,避免曝露過多不必要實作細節,參考以下:static_assert
packed
下方程式編譯後 (gcc 13.3.0) 出現 error: missing binary operator before token "("
已於 commit 9cf7f12 修正。
if-else
,不影響邏輯的情況下,越短的判斷語句應該往前放if-else
深度不宜超過 2 層if
或 else
可省略大括號,而當有任何一分支需要大括號,則其他分支也應加上大括號else
switch
和 case
應在同縮排層級,且若有 case 刻意不使用 break
,則應加上 /*fallthrough*/
的註解:uint64_t
or int64_t
固定長度類型char
是 signed
,例如 char
預設是 unsigned
,顯式使用 signed char