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