2025年9月25日: PostgreSQL 18 釋出!
支援版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6

55.4. 雜項編碼約定 #

C 標準 #

PostgreSQL 中的程式碼僅應依賴於 C99 標準中提供的語言特性。這意味著一個符合 C99 標準的編譯器必須能夠編譯 postgres,至少除了少數平臺相關的部分。

目前,C99 標準中的一些特性不允許在 PostgreSQL 核心程式碼中使用。這目前包括可變長度陣列、宣告與程式碼混排、// 註釋、通用字元名。原因包括可移植性和歷史實踐。

如果提供了回退方案,則可以使用 C 標準的後續修訂版中的特性或編譯器特定的特性。

例如,`_Static_assert()` 和 `__builtin_constant_p` 目前正在使用,儘管它們分別來自 C 標準的新修訂版和 GCC 擴充套件。如果不可用,我們將分別回退使用一個相容 C99 的替代方案,該方案執行相同的檢查,但會發出相當晦澀的訊息,並且不使用 `__builtin_constant_p`。

類函式宏和行內函數 #

宏和帶引數的宏以及 `static inline` 函式都可以使用。後者在作為宏編寫時存在多重求值危險時是首選,例如,在以下情況中:

#define Max(x, y)       ((x) > (y) ? (x) : (y))

或者當宏非常長時。在其他情況下,只能使用宏,或者至少更容易。例如,因為需要將各種型別的表示式傳遞給宏。

當行內函數的定義引用僅作為後端一部分可用的符號(即變數、函式)時,當從前端程式碼包含該函式時,該函式可能不可見。

#ifndef FRONTEND
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
    MemoryContext old = CurrentMemoryContext;

    CurrentMemoryContext = context;
    return old;
}
#endif   /* FRONTEND */

在此示例中,`CurrentMemoryContext` 僅在後端可用,但被引用,因此該函式被 `#ifndef FRONTEND` 隱藏。此規則存在是因為一些編譯器即使在函式未被使用時也會發出對行內函數中包含的符號的引用。

編寫訊號處理程式 #

為了適合在訊號處理程式中執行,程式碼必須非常小心地編寫。根本問題是,除非被阻塞,否則訊號處理程式可以隨時中斷程式碼。如果訊號處理程式中的程式碼使用了與處理程式外的程式碼相同的狀態,則可能導致混亂。例如,考慮當訊號處理程式嘗試獲取中斷程式碼中已持有的鎖時會發生什麼。

除非有特殊安排,否則訊號處理程式中的程式碼只能呼叫非同步訊號安全函式(如 POSIX 中定義的那樣)並訪問 `volatile sig_atomic_t` 型別的變數。PostgreSQL 中的一些函式也被認為是訊號安全的,其中重要的是 `SetLatch()`。

在大多數情況下,訊號處理程式除了記錄訊號已到達之外,不應做任何其他事情,而是使用 latch 喚醒處理程式外部的程式碼。以下是一個此類處理程式的示例:

static void
handle_sighup(SIGNAL_ARGS)
{
    got_SIGHUP = true;
    SetLatch(MyLatch);
}

呼叫函式指標 #

為了清晰起見,如果函式指標是簡單變數,則在呼叫指向的函式時顯式解引用函式指標是首選,例如:

(*emit_log_hook) (edata);

(儘管 `emit_log_hook(edata)` 也會起作用)。當函式指標是結構的一部分時,則額外的標點符號可以而且通常應該省略,例如:

paramInfo->paramFetch(paramInfo, paramId);

提交更正

如果您在文件中看到任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用此表單報告文件問題。