Postgresql 中文操作指南
56.4. Miscellaneous Coding Conventions #
C Standard #
PostgreSQL 中的代码应该仅依赖 C99 标准中提供的语言功能。这意味着符合 C99 标准的编译器必须能够编译 postgres,至少除了几个与平台相关的内容外。
C99 标准中包含的一些功能目前不允许在 PostgreSQL 核心代码中使用。这目前包括可变长度数组、交错声明和代码、// 注释、通用字符名称。原因包括可移植性和历史实践。
如果提供了后备,则可以使用来自 C 标准的更高版本的版本或编译器特定的功能。
例如 Static_assert() 和 builtin_constant_p are currently used, even though they are from newer revisions of the C standard and a GCC extension respectively. If not available we respectively fall back to using a C99 compatible replacement that performs the same checks, but emits rather cryptic messages and do not use _builtin_constant_p。
Function-Like Macros and Inline Functions #
带有参数的宏和 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 隐藏。此规则存在,因为即使该函数未使用,某些编译器也会发出引用内联函数中包含的符号的引用。
Writing Signal Handlers #
为了适合在信号处理程序中运行,必须非常小心地编写代码。根本问题在于,除非被阻止,否则信号处理程序可能会随时中断代码。如果信号处理程序中的代码与外部代码使用相同的状态,则可能会引起混乱。例如,考虑如果信号处理程序尝试获取中断代码中已持有的锁会发生什么情况。
除非有特殊安排,否则信号处理程序中的代码只能调用异步信号安全函数(如 POSIX 中定义的函数)并访问 volatile sig_atomic_t 类型的变量。postgres 中的部分函数也被认为是信号安全的,重要的是 SetLatch()。
在大多数情况下,信号处理程序应该做的不仅仅是注意信号已经到达,并且使用锁闩唤醒在处理程序外部运行的代码。此类处理程序的一个示例如下:
static void
handle_sighup(SIGNAL_ARGS)
{
int save_errno = errno;
got_SIGHUP = true;
SetLatch(MyLatch);
errno = save_errno;
}
保存和恢复 errno,因为 SetLatch() 可能会更改它。如果没有这样做,当前正在检查 errno 的中断代码可能会看到错误的值。
Calling Function Pointers #
为了清楚起见,最好在调用指向的函数时显式解除引用函数指针,如果指针是简单变量,例如:
(*emit_log_hook) (edata);
(尽管 emit_log_hook(edata) 也适用)。当函数指针是结构的一部分时,可以而且通常应该省略额外的标点符号,例如:
paramInfo->paramFetch(paramInfo, paramId);