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 的变量。
postgres 中的少数几个函数也被认为信号安全,
重要的是
SetLatch()。
在大多数情况下,信号处理器应当只记录一个信号已经到达,并使用 一个闩锁唤醒在处理器外部运行的代码。 这样一个处理器的示例如下:
static void
handle_sighup(SIGNAL_ARGS)
{
got_SIGHUP = true;
SetLatch(MyLatch);
}
为了清晰起见,当函数指针是一个简单变量时,在调用被指向的函数时 最好显式地解引用它,例如:
(*emit_log_hook) (edata);
(尽管 emit_log_hook(edata) 也能工作。)
当函数指针是结构的一部分时,额外的标点可以并且通常应当被
省略,例如:
paramInfo->paramFetch(paramInfo, paramId);