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