54.4. Различные соглашения о кодировании#

54.4. Различные соглашения о кодировании

54.4. Различные соглашения о кодировании

C стандарт

Код в Tantor SE должен полагаться только на возможности языка, доступные в стандарте C99. Это означает, что совместимый компилятор C99 должен быть способен компилировать postgres, по крайней мере, за исключением нескольких зависящих от платформы частей.

Некоторые функции, включенные в стандарт C99, в настоящее время не разрешены для использования в основном коде Tantor SE. В настоящее время это включает массивы переменной длины, смешанные объявления и код, комментарии //, универсальные имена символов. Причины для этого включают переносимость и исторические практики.

Функции из более поздних версий стандарта 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);