Skip to content

56.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)
{
    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);