PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

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 的变量。 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);