↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 12 / 11 / 10 / 9.6
历史版本。 PostgreSQL 11 已结束支持。 2023-11-09. 请参阅 当前版本手册.

54.4. 其他编码约定 #

C 标准

PostgreSQL 中的代码应只依赖 C89 标准提供的语言特性。这意味着,至少除去少数依赖平台的部分,符合 C89 标准的编译器必须能够编译 postgres。如果提供了回退方案,则可以使用来自 C 标准后续修订的特性或编译器特定特性。

例如,目前使用了 static inline 和 _Static_assert(),尽管它们来自 C 标准的较新修订。如果这些特性不可用,我们会分别回退为定义不带 inline 的函数,以及使用一种兼容 C89 的替代方案,后者执行相同的检查,但输出的消息比较晦涩。

类函数宏和内联函数

带参数的宏和 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)
{
    int         save_errno = errno;

    got_SIGHUP = true;
    SetLatch(MyLatch);

    errno = save_errno;
}

errno 被保存并恢复,是因为 SetLatch() 可能会改变它。如果不这样做,当前正在检查 errno 的被中断代码可能会看到错误的值。

调用函数指针

为了清晰起见,当函数指针是一个简单变量时,调用其指向的函数时最好显式解引用,例如:

(*emit_log_hook) (edata);

(尽管 emit_log_hook(edata) 也能工作)。当函数指针是某个结构体的一部分时,这些额外符号可以,而且通常也应该省略,例如:

paramInfo->paramFetch(paramInfo, paramId);

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.