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);
如果您在文档中看到任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用此表单报告文档问题。