他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

56.4. その他のコーディング規約 #

標準C #

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)
{
    int         save_errno = errno;

    got_SIGHUP = true;
    SetLatch(MyLatch);

    errno = save_errno;
}

errnoSetLatch()によって変更されるかもしれないので、保存して、リストアされます。 そうしなければ、割り込まれたコードが、現在errnoを参照している場合、誤った値を見ることになるかもしれません。

関数ポインタの呼び出し #

明快にするため、ポインタが単純な変数である場合に指し示す関数を呼び出すときには、関数ポインタを以下の例のように明示的に参照することが望ましいです。

(*emit_log_hook) (edata);

emit_log_hook(edata)でも動作するとしても)。 関数ポインタが構造体の一部であるときには、以下のように、追加的な区切りは省略してよいし、通常は省略すべきです。

paramInfo->paramFetch(paramInfo, paramId);