受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

54.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);

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。