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

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