35

C のインタビューで非常に興味深い質問をされました。特定の g() 関数からのみ呼び出すことができるように、関数 f() をどのように実装できますか。g() 以外の関数が f() を呼び出そうとすると、コンパイラ エラーが発生します。

最初は、関数ポインターを使用してこれを実行できると思っていましたが、実行時に呼び出しをブロックすることに近づくことができました。しかし、コンパイル時の戦略を考えることができませんでした。ansi Cを使用してこれが可能かどうかさえわかりません。

誰にもアイデアはありますか?

4

6 に答える 6

43

1 つの方法を次に示します。

int f_real_name(void)
{
    ...
}

#define f f_real_name
int g(void)
{
    // call f()
}
#undef f

// calling f() now won't work

もう 1 つの方法は、ファイル内の関数が と だけであることを保証できる場合は、 として宣言f()することです。g()f()static

編集: コンパイラ エラーを引き起こす別のマクロ トリック:

static int f(void) // static works for other files
{
    ...
}

int g(void)
{
    // call f()
}
#define f call function

// f() certainly produces compiler errors here
于 2009-09-09T20:06:49.643 に答える
29

g() と f() を同じモジュールに入れ、f() を static として宣言します。static キーワードは、f() を同じモジュールまたはソース ファイル内の関数でのみ使用できるようにします。

また、f() および g() を使用してモジュール内で他のメソッドを許可してはならないことに言及することもできます。そうしないと、f() を呼び出すことができます。

PS - クリス・ルッツの答えが実際には最高だと思います。このアプローチについて言及していますが、より少ない環境条件で動作する巧妙なマクロの名前変更についても言及しています (これら 2 つの機能専用のモジュール ファイルは必要ありません)。

マクロを使用すると、次のことができることにも注意してください。

#define f() f_should_not_be_called_by_anything_except_g

これは適切なエラー メッセージを表示し、ユーザーが f() と入力すると、オート コンプリータ (Visual Studio など) がそのヒントを表示します。

于 2009-09-09T20:06:13.453 に答える
15

static次のキーワードを使用して、モジュールプライベート関数を作成できます。

static void func(void)
{
    // ...
}

次に、func()同じファイルで定義された他の関数によってのみ呼び出すことができます(技術的には、同じ変換単位:ディレクティブに定義が含まれている他の関数#includeは引き続きアクセスできます)。 内部リンケージfuncがあると言われています。他のすべての関数(つまり、キーワードなし)は、外部リンクを持っていると言われます。static

それを超えて、いいえ、関数にアクセスできないようにする方法はありません。マクロを使用して関数の名前を変更できますが、他のコードは常に適切な名前で関数にアクセスできます。

于 2009-09-09T20:08:21.357 に答える
10

GCC のオプションは、ネストされた関数を使用することです。標準 C ではありませんが、非常にうまく機能します。

于 2009-09-09T20:33:50.930 に答える
9

f()g()を同じソース ファイルに配置し、 f()static を宣言します。

于 2009-09-09T20:06:19.287 に答える
3

それは偶然にのみ可能です。

関数f()とg()が両方とも同じソースファイルにあり、ファイルに他の関数がない場合、およびg()がf()への関数ポインターを呼び出し元に返さない場合は、fを作成します。 ()staticがその仕事をします。

他の関数を同じソースファイルに表示する必要がある場合は、ファイルの下部に静的関数としてf()を配置し、その直後にg()を定義するだけで、ほぼ同じ効果が得られます。 '宣言の欠落'でエラーを生成するようにコンパイラーに指示します。他の関数が警告付きで呼び出す可能性があります。

#include <stdio.h>

extern void g(void);    /* in a header */

/* Other functions that may not call f() go here */

static void f(void)
{
    puts("X");
}

void g(void)
{
    f();
}

明らかに、この手法を同じファイル内の別の関数のペア(x​​()とy())に確実に拡張することはできません。そのため、x()とx()のみがy()を呼び出すことができ、g()とg()のみが呼び出すことができます。同時にf()を呼び出すことができます。

ただし、通常は、プログラマーの規律に依存し、ソースファイルでf()を静的にし、g()のみが呼び出すことができるというコメントを付けてから、コードを変更した人を規律して、 g()はf()を呼び出します。

于 2009-09-09T20:13:52.620 に答える