Cの入れ子関数


93

Cで入れ子関数を使用できますか?ネストされた関数の使用は何ですか?Cに存在する場合、それらの実装はコンパイラごとに異なりますか?


1
重複しているようです:stackoverflow.com/questions/1348095/…–
zoli2k

回答:



36

いいえ、Cには存在しません。

Pascalなどの言語で(少なくとも)2つの理由で使用されています。

  1. 名前空間を汚染することなく機能を分解できます。1つ以上のネストされた関数に依存して問題をより小さな論理的な断片に分割することにより、いくつかの複雑なロジックを実装する単一の公開された可視関数を定義できます。
  2. 場合によっては、パラメータの受け渡しが簡単になります。入れ子関数は、すべてのパラメーターと外部関数のスコープ内の一部またはすべての変数にアクセスできるため、外部関数はローカル状態の山を明示的に入れ子関数に渡す必要はありません。

21

ネストされた関数は、の一部ではないANSI Cしかし、彼らはの一部である GNU C


それらがGnu Cの一部である場合、どのような意味がありますか
Sachin Chourasiya

4
@Sachinは、ネストされた関数を含むCコードをgccでコンパイルできる理由を理解するのに役立ちます。情報には教育的価値があります。さらに、C89、C99、またはGNU Cのみに限定されている場合、質問は特定されていません
zoli2k

4
GCCでサポートされている他の言語にはそれらがあります(私が知っているADAとPascal)。Cの実装に追加するのは簡単だったか、サポートする言語の準備のためにCに追加した可能性があります。それらを必要とします。
nategoose 2010

MATLABにはネストされた関数もあります。
mikeTronix 2016

17

いいえ、ネストされた関数をに含めることはできませんC。最も近いのは、別の関数の定義内で関数を宣言することです。ただし、その関数の定義は、他の関数本体の外側に表示する必要があります。

例えば

void f(void)
{
    // Declare a function called g
    void g(void);

    // Call g
    g();
}

// Definition of g
void g(void)
{
}

6
関数gがこのように宣言されている場合、そのスコープは何になりますか?
Sachin Chourasiya

6
宣言のスコープは他の宣言と同じなので、この場合は関数の最後までです。もちろん、の定義がg後でファイルに表示されると、その宣言は残りの翻訳単位のスコープになります。さらに、推奨されていない場合でも、スコープ内で可視の宣言なしにCで関数を呼び出すことができます。
CBベイリー

5

Cでコーディングしている多くの人がC ++コンパイラ(Visual C ++やKeil uVisionなど)を使用してこれを行っているので、これについて言及します。

Cではまだ許可されていませんが、C ++を使用している場合は、C ++ 11で導入されたラムダ関数を使用して同じ効果を得ることができます。

void f()
{
    auto g = [] () { /* Some functionality */ }

    g();
}

4
問題はC ++ではなくCに限定されていました
Virgile

11
@Virgile-また、「他の言語でネストされた関数は許可されていますか?」という質問も具体的に述べられています。ジョンの答えは私を助けました。
www-0av-Com 2015

3

他の人が答えたように、標準Cはネストされた関数をサポートしていません。

一部の言語では、入れ子関数を使用して、複数の関数と変数をコンテナー(外部関数)に格納し、個々の関数(外部関数を除く)と変数が外部から見えないようにします。

Cは、これは、別のソースファイルにこのような機能を置くことによって行うことができます。main関数をグローバルとして定義し、他のすべての関数と変数をstaticとして定義します。これで、メインモジュールのみがこのモジュールの外に表示されます。


再帰outer-> nested-> outer-> nestedがある場合は、2つの異なるフレームが保持されるint declared_in_outerためdeclared_in_outer、静的グローバルとして配置することはできません。
エイドリアンPanasiuk 2013年

1

2番目の質問に答えるために、ネストされた関数を定義できる言語があります(リストは、nested-functions-language-list-wikipediaにあります)。

これらの言語の中で最も有名なものの1つであるJavaScriptでは、ネストされた関数(クロージャーと呼ばれる)の1つは次のとおりです。

  • オブジェクトのコンストラクターでクラスメソッドを作成します。
  • セッターとゲッターと共にプライベートクラスメンバーの機能を実現するため。
  • グローバルネームスペースを汚染しないこと(もちろん、すべての言語に当てはまります)。

いくつか例を挙げると...


0

または、それについて賢く、プリプロセッサを有利に使用することができます(source.c):

#ifndef FIRSTPASS
#include <stdio.h>

//here comes your "nested" definitions
#define FIRSTPASS
#include "source.c"
#undef FIRSTPASS

main(){
#else
    int global = 2;
    int func() {printf("%d\n", global);}
#endif
#ifndef FIRSTPASS
    func();}
#endif

-1

これはCの入れ子関数ではありませんか?(関数displayAccounts())

関数を別の方法で定義して変数を渡したとしても、アカウントを複数回印刷する必要があるのでうまくいきません。

(学校の宿題から取ったスニペット)...

//function 'main' that executes the program.
int main(void)
{
    int customerArray[3][3] = {{1, 1000, 600}, {2, 5000, 2500}, {3, 10000, 2000}};  //multidimensional customer data array.
    int x, y;      //counters for the multidimensional customer array.
    char inquiry;  //variable used to store input from user ('y' or 'n' response on whether or not a recession is present).

    //function 'displayAccounts' displays the current status of accounts when called.
    void displayAccounts(void)
    {
        puts("\t\tBank Of Despair\n\nCustomer List:\n--------------");
        puts("Account #    Credit Limit\t  Balance\n---------    ------------\t  -------");
        for(x = 0; x <= 2; x++)
        {
            for(y = 0; y <= 2; y++)
                printf("%9d\t", customerArray[x][y]);
            puts("\n");
        }
    }

    displayAccounts();  //prints accounts to console.
    printf("Is there currently a recession (y or n)? ");


//...

    return 0;
}

4
これは合法的な標準Cではありません。コンパイラで動作する場合は、コンパイラが標準C言語の拡張機能を提供しているためです。ある意味では、あなたのコンパイラは厳密C.、ないに言えば、ある別の言語を、コンパイルされた
ネイト・エルドリッジ

ご入力ありがとうございます。それ以来、関数を宣言、定義、使用する適切な方法を学びました。これを振り返ると少し恥ずかしいです>。<
midnightCoder

1
@midnightCoder:回答はいつでも削除できます:)
chqrlie
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.