53.4. Различные соглашения о кодировании#
53.4. Различные соглашения о кодировании #
C стандарт #
Код в Tantor BE должен полагаться только на возможности языка, доступные в стандарте C99. Это означает, что совместимый компилятор C99 должен быть способен компилировать postgres, по крайней мере, за исключением нескольких зависящих от платформы частей.
Некоторые функции, включенные в стандарт C99, в настоящее время не разрешены для использования в основном коде Tantor BE. В настоящее время это включает массивы переменной длины, смешанные объявления и код, комментарии //
, универсальные имена символов. Причины для этого включают переносимость и исторические практики.
Функции из более поздних версий стандарта 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);